C语言实现KMP算法与扩展字符串匹配练习
KMP算法是处理字符串匹配问题的高效工具,通过预处理模式串获取部分匹配表(Next数组),避免回溯主串指针。本文将展示该算法在C语言中的标准实现,并进一步探讨解决包含中括号通配符条件的扩展匹配问题。
核心原理:构建Next数组
KMP算法的关键在于计算模式串的 next 数组。该数组记录了当匹配失败时,模式串指针应回退的最长公共前后缀长度位置。以下是获取该值的C语言实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_nextval(char *pattern, int next[])
{
//get the next value of the pattern
int i = 0, j = -1;
next[0] = -1;
int patlen = strlen(pattern);
while ( i < patlen - 1){
if ( j == -1 || pattern[i] == pattern[j]){
++i;
++j;
if (pattern[i] != pattern[j])
next[i] = j;
else
next[i] = next[j];
}
else
j = next[j];
}
return(0);
}
完整流程:KMP匹配索引查询
在获得 next 数组后,即可通过一次遍历查找目标串中模式串首次出现的位置。该方法利用预处理的跳转信息跳过无效比较,显著提升性能。
int kmpindex(char *target, char *pattern, int pos)
{
int tari = pos, pati = 0;
int tarlen = strlen(target), patlen = strlen(pattern);
int *next = (int *)malloc(patlen * sizeof(int));
get_nextval(pattern, next);
while ( tari < tarlen && pati < patlen ){
if (pati == -1 ||target[tari] == pattern[pati]){
++tari;
++pati;
}else{
pati = next[pati];
}
}
if(next != NULL) free(next);
next = NULL;
if (pati == patlen)
return tari - pati;
else
return -1;
}
int main()
{
char target[50], pattern[50];
printf("imput the target:\n" );
scanf("%s",target);
printf("imput the pattern:\n" );
scanf("%s",pattern);
int ans = kmpindex(target,pattern,0);
if (ans == -1)
printf("error\n");
else
printf("index:%d\n",ans);
return 0;
}
进阶挑战:支持中括号通配符的匹配
在某些特定场景中,字符串可能包含用中括号表示的模式匹配规则。例如 “aa[123]bb” 代表 “aa1bb”、“aa2bb” 或 “aa3bb” 均可视为有效匹配。下面针对此类需求提供一套C语言的完整解决方案:
题目逻辑要求读入多组数据,每组包含 N 个待查字符串及一个带有特殊格式的主字符串。系统需输出所有匹配到的行号及对应的原始字符串(匹配过程不区分大小写)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1001
#define LEN 101
struct str
{
char name[101];
};
int main()
{
struct str strs[MAX];
struct str t[LEN];
int i, n, len, j, k, left, right, count, flag;
char text[LEN], newtext[LEN];
while (scanf("%d", &n) != EOF) {
// 接收数据
getchar();
for (i = 0; i < n; i ++) {
scanf("%s", strs[i].name);
}
// 接收文本串
getchar();
gets(text);
len = strlen(text);
for (i = left = right = 0; i < len; i ++) {
if (text[i] == '[') {
left = i;
} else if (text[i] == ']') {
right = i;
break;
}
}
count = right - left - 1;
if (count <= 0) { // 没有正则匹配
for (i = j = 0; i < len; i ++) {
if (text[i] != '[' && text[i] != ']') {
newtext[j ++] = text[i];
}
}
newtext[j] = '\0';
for (i = 0; i < n; i ++) {
if (strcasecmp(strs[i].name, newtext) == 0) {
printf("%d %s\n", i + 1, strs[i].name);
}
}
}else { // 需要正则匹配
for (j = 1, k = 0; j <= count; j ++, k ++) { // 构建文本数组
memset(t[k].name, '\0', sizeof(t[k].name));
for (i = 0; i < left; i ++) {
t[k].name[i] = text[i];
}
t[k].name[i] = text[left + j];
strcat(t[k].name, text + right + 1);
}
// 正则匹配
for (i = 0; i < n; i ++) {
for (j = flag = 0; j < count; j ++) {
if (strcasecmp(strs[i].name, t[j].name) == 0) {
flag = 1;
break;
}
}
if (flag) {
printf("%d %s\n", i + 1, strs[i].name);
}
}
}
}
return 0;
}
上述代码首先定位中括号范围以确定生成多少种候选分支。若无特殊字符则直接执行不区分大小写的字符串比对;若有,则在循环中动态构造多个变体逐一验证。此方法适用于中小规模数据的精确模式搜索任务。
以上就是使用C语言解决字符串匹配问题的详细内容,更多关于KMP算法在C语言中应用及扩展匹配技巧的资料请关注本站其它相关文章!免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









