C 长文本字符串中的模式匹配

C 长文本字符串中的模式匹配,c,C,我写了这段代码,它在某些情况下是有效的。然而,有时它会失败,我就是不明白为什么。有人能帮我找出错误吗 它适用于: 字符串:ishanthakkar-ishan 模式:ishan 但它失败于: 字符串:cpr编程 模式:cpr 资料来源: #include <stdio.h> #include <stdlib.h> #include <string.h> int *compute_prefix_function(char *pattern, i

我写了这段代码,它在某些情况下是有效的。然而,有时它会失败,我就是不明白为什么。有人能帮我找出错误吗

它适用于: 字符串:
ishanthakkar-ishan
模式:
ishan

但它失败于:

字符串:
cpr编程
模式:
cpr

资料来源:

#include <stdio.h>    
#include <stdlib.h>    
#include <string.h>

int *compute_prefix_function(char *pattern, int psize)
{
    int k = -1;
    int i = 1;
    int *pi = malloc(sizeof(int)*psize);
    if (!pi)
        return NULL;

    pi[0] = k;
    for (i = 1; i < psize; i++) {
        while (k > -1 && pattern[k+1] != pattern[i])
            k = pi[k];
        if (pattern[i] == pattern[k+1])
            k++;
        pi[i] = k;
    }
    return pi;
}
#包括
#包括
#包括
int*计算前缀函数(char*模式,int psize)
{
int k=-1;
int i=1;
int*pi=malloc(sizeof(int)*psize);
if(!pi)
返回NULL;
pi[0]=k;
对于(i=1;i-1&&pattern[k+1]!=pattern[i])
k=pi[k];
if(模式[i]==模式[k+1])
k++;
pi[i]=k;
}
返回pi;
}
//此函数在O(n)时间内查找匹配字符串,因此在找到不匹配字符时,只需迭代文本字符串一次;它继续下一个字符,并开始与要搜索的字符串的第一个字符(即模式)进行比较

int kmp(char *target, int tsize, char *pattern, int psize)
{
    int i;
    int *pi = compute_prefix_function(pattern, psize);
    int k = -1;
    if (!pi)
        return -1;

    for (i = 0; i < tsize; i++) {
        while (k > -1 && pattern[k+1] != target[i])
            k = pi[k];
        if (target[i] == pattern[k+1])
            k++;

        if (k == psize - 1) {
            free(pi);
            return i-k;
        }
    }

    free(pi);
    return -1;
}

int main(int argc, const char *argv[])
{
    char target[200];
    char *ch = target;
    char pattern[20];
    int i;

    printf("Enter the string: \n");
    fgets(target,100,stdin);

    printf("Enter the string to be matched: \n");
    fgets(pattern,20,stdin);

    i = kmp(target, strlen(target), pattern, strlen(pattern)); 
    if (i >= 0)
        printf("matched @: %s\n", ch + i);

    getch();
    return 0;
}
intkmp(char*target、inttsize、char*pattern、intpsize)
{
int i;
int*pi=计算前缀函数(模式,psize);
int k=-1;
if(!pi)
返回-1;
对于(i=0;i-1&&pattern[k+1]!=target[i])
k=pi[k];
if(目标[i]==模式[k+1])
k++;
if(k==psize-1){
自由(pi);
返回i-k;
}
}
自由(pi);
返回-1;
}
int main(int argc,const char*argv[]
{
字符目标[200];
char*ch=目标;
字符模式[20];
int i;
printf(“输入字符串:\n”);
fgets(目标,100,标准偏差);
printf(“输入要匹配的字符串:\n”);
fgets(模式,20,标准);
i=kmp(目标,strlen(目标),模式,strlen(模式));
如果(i>=0)
printf(“匹配@:%s\n”,ch+i);
getch();
返回0;
}
fgets函数读取并在字符串中包含结尾CR(或CRLF)

添加一个
chomp()
函数,如

void chomp(char *s) {
    int n = strlen(s);
    while (n && (s[n-1]==10 || s[n-1]==13)) s[--n] = 0;
}
删除字符串末尾的所有CR或LF。
然后在调用
kmp()
之前(以及在
scanf()之后)选择模式和目标

程序应该表现得更好


注意:
10
'\n'
(左)和
13
'\r'
(CR)

获得线索:

i = kmp(target, strlen(target), pattern, strlen(pattern)); 
正在传递字符串长度+1(对于空字符),因此对某些文本字符串给出了错误结果

i = kmp(target, strlen(target)-1, pattern, strlen(pattern)-1); 
适用于所有情况


谢谢你们大家抽出时间

尽量正确地缩进代码-不需要额外的空格。您能对代码进行注释以便清楚各个部分的意图吗?据我所知,像
kmp()
这样的函数不是标准计算词典的一部分,您只声明程序进行“模式匹配”,而从未指定这意味着什么。据我们所知,代码可能是正确的。@John:很抱歉给您带来不便,我添加了一些描述来理解这个程序。实际上我还没有编写完整的程序,所以我也有一些困惑@JohnZwinck:
kmp
在字符串算法中是明确的Knuth Morris Pratt。我在kmp()函数中犯了一些错误。因为它适用于文本字符串和模式,比如jiahkhan和jiah,对于jiah和jiahkhanI返回-1,尽管这应该可以工作!我试图删除CR和LF,但在这种情况下,它对任何情况都不起作用!你添加了chomp函数了吗?在调用kmp之前,对每个变量调用两次?它在这里工作…是的,我用另一种方式做的!感谢buddy ring0,你离我的解决方案很近:)@ring0这些应该写为LF的
'\n'
,CR的
'\r'
,不是吗?此外,字符串终止符更清楚地写为
'\0'
@unwind Agreed for CR/LF,10和13并不那么有名。至于
0
vs
'\0'
,我喜欢使用
0
,因为许多初学者将
'\0'
视为一个特殊字符,而在C中,这只是0的1字节整数值。这有助于从C的基本原理考虑C。
i = kmp(target, strlen(target)-1, pattern, strlen(pattern)-1);