全是套路——字符串通配符

华为OJ的题:

问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
*:匹配0个或以上的字符(字符由英文字母和数字0-9组成,不区分大小写。下同)
?:匹配1个字符


输入:
通配符表达式;
一组字符串。


输出:
返回匹配的结果,正确输出true,错误输出false

在OJ里面是初级题。最近脑子很笨,反应不过来。也是在网上看了思想之后才编出来的。

具体思想:

1.由于*可以代替任意字符,所以*先要忽略

2.?可以代替一个字符,所以将它考虑到当中

3.以*为分隔符来分割字符串,现在字符串是一系列的字符。如果第一个字符跟整体匹配上了,下一个字符接着上一个匹配的末尾继续匹配,以此类推,都匹配成功就算匹配成功。

4.字符串的匹配因为涉及到?,不能直接用string的find。所以用kmp算法。

KMP具体来说,就是在原字符串中找到第一个与匹配字符串相同的字母,然后依次匹配若成功则返回,若失败,则记录失败的位置,下次从失败的位置开始匹配。这样可以提高效率。

注:对于?匹配其实没有那么麻烦,只有在if语句中加上一个||就可以了如果匹配字符串中的那个位是?就默认匹配成功。

上代码:

#include <stdio.h>
#include <iostream>
#include <stack>
#include <string>
#include <vector>

using namespace std;

char daxie(char c)
{
    if (c >= 'A'&&c <= 'Z')
    {
        c = c - 'A' + 'a';
    }
    return c;
}

int pipei(string S, string T)
{
    int index = 0;
    for (int i = index; i < S.size(); i++)
    {
        if (S[i] == T[0]||T[0]=='?')
        {
            int k;
            for (k = 0; k < T.size() && k+i <S.size() ; k++)
            {
                if (S[k+i] == T[k]||T[k]=='?')
                {

                }
                else
                {
                    index = k + i;
                    break;
                }
            }
            if (k == T.size() )
            {
                return i;
            }
        }
    }
    return -1;
}

int main()
{
    string str1, str2;
    while (cin >> str1>>str2)
    {
        for (int i = 0; i < str1.size(); i++)
        {
            str1[i] = daxie(str1[i]);
        }
        for (int i = 0; i < str2.size(); i++)
        {
            str2[i] = daxie(str2[i]);
        }
        vector<string> a;
        int pos = -1;
        while ((pos = str1.find('*')) != string::npos)
        {
            a.push_back(str1.substr(0, pos));
            str1 = str1.erase(0, pos + 1);
        }
        a.push_back(str1);
        for (int i = 0; i < a.size(); i++)
        {
            if (a[i] == "")
            {
                a.erase(a.begin() + i, a.begin() + i + 1);
            }
        }
        int i;
        for (i = 0; i < a.size(); i++)
        {
            int pos = -1;
            if ((pos = pipei(str2, a[i])) < 0)
            {
                cout << "false" << endl;
                break;
            }
            else
            {
                str2 = str2.erase(0, pos + a[i].size());
            }
        }
        if (i == a.size())
        {
            cout << "true" << endl;
        }
        
        int kk = 0;
    }

    return 0;

}

注意:此代码是有些问题的。比如你输入*,按道理是都能匹配的,但是有字符串分割没有成功,所以会失败,但是就不更改了。

还有一个问题,虽然华为的系统没有检测,但是还是不能忽略的。

*只能代表数字和字母,并不能匹配除这以外的。(可能是华为的测试样例也没有考虑吧)

所以如果输入*.* 和...也会匹配成功,这是不严谨的。所以说匹配的时候,在跳过的那几个串中要检测有没有*不能替代的字符,如果算不匹配。

原文地址:https://www.cnblogs.com/wyc199288/p/5647635.html