C 将字符串与通配符进行比较

C 将字符串与通配符进行比较,c,arrays,string,C,Arrays,String,在C语言中,如何将包含*(可以是任意字符组合)的字符串与二维字符串矩阵进行精确比较 例如,我有一个单词go*s。它可以生成单词“华丽”(*是“orgeou”)、“善良”、“山羊”、“goes”等。我应该从整本字典中阅读这些单词,并将它们与包含一个或多个星号的单词进行比较(*)。必须打印由带星号的单词生成的每个单词。如果两个单词的长度相同,则比较容易,因为*只能是一个字母 int fq(char *s1, char *s2){ int i, a=0, b=0, s=0; while (1){

在C语言中,如何将包含
*
(可以是任意字符组合)的字符串与二维字符串矩阵进行精确比较

例如,我有一个单词
go*s
。它可以生成单词“华丽”(
*
是“orgeou”)、“善良”、“山羊”、“goes”等。我应该从整本字典中阅读这些单词,并将它们与包含一个或多个星号的单词进行比较(
*
)。必须打印由带星号的单词生成的每个单词。如果两个单词的长度相同,则比较容易,因为
*
只能是一个字母

int fq(char *s1, char *s2){
int i, a=0, b=0, s=0;
while (1){
    if (s1[a]=='\0')
        break;
    a++;
}
if (strlen(s1)==strlen(s2)){
    for(i=0; i<a; i++){
        if (s1[i]=='*'){
            b++;
            }
        if (s1[i]==s2[i]){
            b++;
            }
        }
    }
if (b==a)
    return 1;
intfq(字符*s1,字符*s2){
int i,a=0,b=0,s=0;
而(1){
如果(s1[a]='\0')
打破
a++;
}
if(strlen(s1)=strlen(s2)){

对于(i=0;i,以下内容将使用包含单个
*
的输入字符串

  • 开始在输入字的开头一次比较一个字符
  • 如果遇到
    *
    ,请向后比较最后一个字符中的两个字符串
  • 如果不匹配,则返回
    0
  • 如果您遇到
    *
    问题,您就完成了
  • 如果不匹配,则返回
    0

  • (补充:此算法也适用于第一个或最后一个位置的
    *

    您可以检查前两个字符是否为“go”,最后一个字符是否为“s”

    最简单的方法是使用一个简单的条件:

    if (strncmp(str, "go", 2) == 0 && str[strlen(str) - 1] == 's')
    
    strlen(str) >= 2
    
    如果字符串匹配,则strncmp返回0

    您还应确保字符串长度至少为2个字符,否则在比较字符串的2个字符时会出现分段错误,您可以在上述条件中添加:

    if (strncmp(str, "go", 2) == 0 && str[strlen(str) - 1] == 's')
    
    strlen(str) >= 2
    

    通过逐个字符检查模式字符串并应用以下规则,您可以非常轻松地编写递归函数,将sting与另一个包含通配符的字符串进行比较:

    • 如果模式[p]='\0':如果候选模式[c]='\0',则模式匹配
    • 如果模式[p]='*':尝试将候选[c]…候选[c+n]与模式[p+1]匹配
    • 如果模式[p]!=“?”和模式[p]!=候选者[c]:不匹配
    • 否则,将模式[p+1]与候选[c+1]匹配
    这几条规则可以轻松地编写为用于匹配的递归函数:

    #include <stdbool.h>
    
    bool match(const char *pattern, const char *candidate, int p, int c) {
      if (pattern[p] == '\0') {
        return candidate[c] == '\0';
      } else if (pattern[p] == '*') {
        for (; candidate[c] != '\0'; c++) {
          if (match(pattern, candidate, p+1, c))
            return true;
        }
        return match(pattern, candidate, p+1, c);
      } else if (pattern[p] != '?' && pattern[p] != candidate[c]) {
        return false;
      }  else {
        return match(pattern, candidate, p+1, c+1);
      }
    }
    

    这不是一种有效的方法,但我认为它很容易理解和实现。如果您需要更有效的方法,可以从以下方面入手:

    不久前有过同样的问题,并提出了这个问题。只传递一次主字符串就可以提高效率,而不必使用递归函数。如果您偶然发现了这个线程,hopef很高兴你发现这很有帮助

    #include <stdio.h>
    
    _Bool wildcard_strcmp(char *line, char *pattern)
    {
        _Bool wildcard = 0;
        char *placeholder;
    
        do
        {
            if ((*pattern == *line) || (*pattern == '?'))
            {
                line++;
                pattern++;
            }
            else if (*pattern == '*')
            {
                if (*(++pattern) == '\0')
                {
                    return 1;
                }
                wildcard = 1;
            }
            else if (wildcard)
            {
                if (pattern == placeholder)
                {
                    line++;
                }
                else
                {
                    pattern = placeholder;
                }
            } 
            else
            {
                return 0;
            }
        } while (*line);
    
        if (*pattern == '\0')
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
    
    int main()
    {
        char string[200] = "foobarfoobar";
        char pattern[200] = "fo?*barfoo*";
    
        if (wildcard_strcmp(string, pattern))
        {
            printf("Match\n");
        }
        else
        {
            printf("No Match\n");
        }
    
        return 0;
    }
    
    #包括
    _布尔通配符\u strcmp(字符*行,字符*模式)
    {
    _布尔通配符=0;
    字符*占位符;
    做
    {
    如果((*pattern==*line)| |(*pattern=='?'))
    {
    line++;
    模式++;
    }
    如果(*模式=='*'),则为else
    {
    如果(*(++模式)='\0')
    {
    返回1;
    }
    通配符=1;
    }
    else if(通配符)
    {
    if(模式==占位符)
    {
    line++;
    }
    其他的
    {
    模式=占位符;
    }
    } 
    其他的
    {
    返回0;
    }
    }而(*行);
    如果(*模式=='\0')
    {
    返回1;
    }
    其他的
    {
    返回0;
    }
    }
    int main()
    {
    字符字符串[200]=“foobarfoobar”;
    字符模式[200]=“fo?*barfoo*”;
    if(通配符\u strcmp(字符串、模式))
    {
    printf(“匹配\n”);
    }
    其他的
    {
    printf(“不匹配\n”);
    }
    返回0;
    }
    
    您确实应该查看正则表达式库,例如
    regcomp(3)
    。man是您的朋友。glob是您的朋友。%man 3glob@CharlieBurns你是说。
    glob(3)
    仅适用于文件名。哈。这很奇怪。我本可以发誓我使用glob来匹配字符串。但那是几年前的事了。也许我自己的库中有一个特殊版本。根据OP,该模式可能包含一个或多个星号。该算法是否适用于多个星号模式?@user4815162342:这是一个公平的问题。调用此函数会再次出现rsively可能有效,但这只是一个猜测。在这种情况下,只需向前检查(尽管对于单个星号,从末尾开始要快得多).我曾想过这样做,但当时我的脑海中似乎不太清楚。但现在我想这几乎是最好的方法。但当一个单词包含多个星号时会发生什么?(非常小的音符)<代码> Boo< <代码> >代码>真< /代码>和代码> false 是C++。请确保<代码>包含< <代码>。C。谢谢。我还有一个问题。如果一个单词中包含任意数量的(?),那么这个词是否也可以工作?问号可以是英文字母表中的任何字符。例如,“?”可以生成单词“poeters”,因此函数应该返回1。不是直接返回,但是您可以很容易地修改最后一个else if语句,如下所示:(pattern[p]!='?'&&pattern[p]!=candidate[c])。@imreal似乎您翻转了“pattern”和“candidate”最后两种情况的参数。当前,您询问
    *cdxcd
    是否与模式
    zcdxcdxcd
    匹配,而不是相反。@imreal近似为O(n^m),其中“n”是字符串中的字符数,“m”是模式中的星星数。如果你关心效率,你可能想要更高效的东西,这是为了简单而写的,不是为了速度。