由字符数组表示的字符串中的模式匹配

问题描述 投票:0回答:1

我正在尝试仅使用数组(文本是字符数组)来解决一个非常基本的问题,但我在实现一些特定的东西时遇到了问题。

因此,我正在尝试编写一个函数,该函数接受两个字符数组作为参数 - 即文本和模式 - 并返回该模式在文本中出现的次数(文本中有多少个不同的子字符串与该模式匹配)。文本仅由数字和拉丁字母组成。该模式可能包含以下特殊字符(不能出现在文本中):

“*” - 恰好对应一个任意字符; “%” - 对应一位或两位数字(来自十进制数字系统); “@” - 对应一个拉丁字母。

让我们分析一些例子:

文字:“te3t zdrte44q t33t”

模式:“t*%@”

说明:

模式“t*%@”可以匹配“te3a”、“t337q”等子字符串。*对应于任意一个字符,%对应于一位或两位数字,@对应于一个拉丁字母。

在给定文本“te3t zdrte44q t33t”中,模式匹配三个子字符串:“te3t”、“te44q”和“t33t”。

因此,此示例的预期输出为 3。

文字:“aaaaaa”

模式:“aa”

预期产量:5

文字:“123”

模式:“%%”

预期输出:3

我在模式符号 * 和 @ 方面取得了很大进展。它们运行良好,与预期的一个角色完全匹配。然而,我在 % 方面遇到了一些障碍。与其他符号不同,它不仅可以匹配一个符号,有时还可以匹配两个符号,这让我有点头疼。

看,棘手的部分是 % 没有固定长度。它是可变的,因此它可以在一个实例中匹配一个符号,在另一个实例中匹配两个符号。事实证明,弄清楚如何处理这种动态匹配对我来说有点具有挑战性。

如果您对如何解决此问题有任何想法或建议,我非常感谢您的意见。

这是我到目前为止的代码:

#include <iostream>

using namespace std;

const int MAX_SIZE_TEXT = 201;
const int MAX_SIZE_PATTERN = 201;

unsigned getStrLen(char str[])
{
    int i = 0, count = 0;

    while (str[i] != '\0')
    {
        i++;
        count++;
    }

    return count;
}

bool isLetter(char ch)
{
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}

bool isDigit(char ch)
{
    return ch >= '0' && ch <= '9';
}

unsigned countMatches(char text[], char pattern[])
{
    int textLen = getStrLen(text);
    int patternLen = getStrLen(pattern);

    int i = 0, j = 0, currentLen = 0, matches = 0;

    bool matchedASingleDigit = false;
    while (i < textLen)
    {
        cout << text[i] << "?=" << pattern[j] << endl;
        if (text[i] == pattern[j] || pattern[j] == '*' 
            || (pattern[j] == '@' && isLetter(text[i])))
        {
            cout << "(before) i=" << i << "; j=" << j << endl;
            currentLen += 1;
            i++;
            j++;
            cout << "(after) i=" << i << "; j=" << j << endl;

            cout << "currentLen = " << currentLen << endl;
            if (currentLen == patternLen)
            {
                matches++;
            }
        }
        else if (pattern[j] == '%')
        {
            /*if (isDigit(text[i]))
            {
                matchedASingleDigit = true;
                currentLen += 1;
                i++;
                j++;
                cout << "(after) i=" << i << "; j=" << j << endl;

                cout << "currentLen = " << currentLen << endl;
                if (currentLen == patternLen)
                {
                    matches++;
                }
            }

            if (i < textLen - 1 && isDigit[text])*/
        }
        else
        {
            i -= currentLen - 1;
            j = 0;
            cout << "(after) i=" << i << "; j=" << j << endl;
            
            currentLen = 0;
            cout << "currentLen = " << currentLen << endl;
        }
    }

    return matches;
}

void testCountingMatches()
{
    char text[MAX_SIZE_TEXT];
    cin.getline(text, MAX_SIZE_TEXT);

    char pattern[MAX_SIZE_PATTERN];
    cin.getline(pattern, MAX_SIZE_PATTERN);

    unsigned matches = countMatches(text, pattern);

    cout << matches << endl;
}

int main()
{
    testCountingMatches();  
}
c++ arrays char
1个回答
0
投票

对于初学者,您可以使用递归。

unsigned countSingle(char text[], char pattern[])
{
    if(text[0] == '\0' || pattern[0]=='\0')
    {
        return pattern[0]=='\0';
    }
    if (text[0] == pattern[0] || pattern[0] == '*' 
            || (pattern[0] == '@' && isLetter(text[0])))
    {
        return countSingle(text + 1, pattern + 1);
    }
    else if(pattern[0] == '%')
    {
        int percentCount;
        for(percentCount = 0; pattern[percentCount] == '%'; percentCount++);
        int digitCount = 0;
        for(int digitCount = 0; digitCount < percentCount; digitCount++)
        {
            if(!isDigit(text[digitCount]))
            {
                return 0;
            }
        }
        text += percentCount - 1;

        int matches = 0;
        for(int digitCount = 0; digitCount < percentCount; digitCount++)
        {
            if(isDigit(text[digitCount]))
            {
                matches += countSingle(text + digitCount, pattern + percentCount);
            }
            else
            {
                return matches;
            }
        }
        return matches;
    }
    return 0;
}

unsigned countMatches(char text[], char pattern[])
{
    int textLen = getStrLen(text);
    int patternLen = getStrLen(pattern);

    int i = 0, j = 0, currentLen = 0, matches = 0;

    for(i = 0; i < getStrLen(text); i++){
        matches += countSingle(text + i, pattern);
    }

    return matches;
}

这里我们首先将不同的

i
的计数分解到它自己的函数中,然后我们可以利用递归来推进文本和模式指针。我已使代码尽可能接近您的原始代码。百分号很棘手,正如 @SamVarshavchik 所评论的,如果有
n
连续的百分号,您需要考虑在继续匹配之前从
n
跳到
2n
。这是通过在递归中使用求和来实现的。

现在正如 @n.m.couldbeanAI 评论的那样,要使模式匹配高效并不那么容易。这并不是为了提高效率,只是为了给你一个想法,因为你陷入了困境。

演示:https://godbolt.org/z/rhYcx4hv1

© www.soinside.com 2019 - 2024. All rights reserved.