在C语言中,字符串匹配可以使用strstr()函数实现。返回指向str1中第一个出现的str2的指针,如果str2不是str1的一部分,则返回空指针。
char* strstr(const char* string ,const char* strCharSet);
//在一个字符串里查找所求字符串
1.strstr()函数的使用
#include<iostream>
using namespace std;
//字符串匹配
int main(){
char* str = "hello world";
char* t = "llo";
char* st=strstr(str,t);
cout << st << endl;
}
2.模拟strstr()函数
在字符串里查找所给字符串,我们称之为模式匹配。
1.朴素的模式匹配
a.模拟实现字符串匹配,返回所查询字符串的下标
//模拟实现字符串匹配,返回所查询字符串的下标
int my_strstr(const char* str1, const char* str2){
assert(str1!=NULL&&str2!=NULL);
int i, j;
i = j = 0;
while (str1[i]!='\0'&&str2[j]!='\0'){
if (str1[i]==str2[j]){
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (str2[j] == '\0')
return i - j;
return -1;
}
b.模拟实现字符串匹配,返回所查询字符及之后的字符串
char* my_strstr(const char* str1, const char* str2){//模拟实现字符串匹配,返回所查询字符及之后的字符串
assert(str1 != NULL&&str2 != NULL);
int i, j;
i = j = 0;
while (str1[i] != '\0'&&str2[j] != '\0'){
if (str1[i] == str2[j]){
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (str2 [j]== '\0')
return (char*)str1+i-j;
return NULL;
}
int main()
{
char* str1 = "abababcabab";
char* str2 = "abc";
char* str=my_strstr(str1,str2);
if (str!=NULL)
cout << str;
else
cout << "不存在";
}
运行结果:
c.kmp算法
在上面程序中,从比较规则上来说,在一次比较中没有匹配,在下一次比较中,又要重新再一次比较前面重复的字符。从这个角度而言,已经比较过的重复的字符没有比较的意义的,因为回溯的次数太多次。
kmp算法的作用是在已知的字符串中查找字串的位置,也叫做串的模式匹配。KMP算法字符串移位的关键就在于最长相等前后缀的长度。
实现next数组:
int *get_next(char* str,int next[],int size){//求解next[]数组,得到前缀表
int i = 0;//指向前缀的末尾端
int j = 1;//指向后缀的起始段
next[0] = 0;
while (size--){
if (str[i] == str[j]){
next[j] = next[j - 1] + 1;
i++;
j++;
}
else{
next[j] = 0;
i = 0;
j++;
}
}
return next;
}
实现KMP算法:
int KMP(char* str1, char* str2, int next[]){
int i, j;
i = 0; j = 0;
while (str1[i] != '\0'&&str2[j] != '\0'){
if (str1[i] == str2[j]){
i++;
j++;
}
else
{
if (j > 0)//考虑到如果如果当j跳到0时,那么在进行j-1会出现溢出
j = next[j - 1];
else{
j = 0;
if (str1[i] != str2[j])
i++;
}
}
}
if (str2[j] == '\0')
return i - j + 1;
else
return -1;
}
最终代码及结果:
#include<iostream>
using namespace std;
int *get_next(char* str,int next[],int size){//求解next[]数组,得到前缀表
int i = 0;//指向前缀的末尾端
int j = 1;//指向后缀的起始段
next[0] = 0;
while (size--){
if (str[i] == str[j]){
next[j] = next[j - 1] + 1;
i++;
j++;
}
else{
next[j] = 0;
i = 0;
j++;
}
}
return next;
}
int KMP(char* str1, char* str2, int next[]){//利用前缀表进行匹配,总感觉自己写到好冗余啊
int i, j;
i = 0; j = 0;
while (str1[i] != '\0'&&str2[j] != '\0'){
if (str1[i] == str2[j]){
i++;
j++;
}
else
{
if (j > 0)//考虑到如果如果当j跳到0时,那么在进行j-1会出现溢出
j = next[j - 1];
else{
j = 0;
if (str1[i] != str2[j])
i++;
}
}
}
if (str2[j] == '\0')
return i - j + 1;
else
return -1;
}
int main(){
char str1[] = "abcabcabcdefg";
char str2[] = "defg";
int size = sizeof(str2) / sizeof(str2[0]) - 1;
int* next =(int*)malloc(sizeof(int)*size);
get_next(str2, next, size);//利用get_next()函数,求出next[]数组
int n = KMP(str1,str2,next);
if (n != -1)
cout << "存在所求字符串" <<"在字符串的"<<n<<"位置"<< endl;
else
cout << "不存在" << endl;
}
以上都是我个人所思所得,如果有错误,欢迎在评论区指正。