思路:
通过字符串匹配算法找到模式在文本中出现的位置,再删除文本中的模式后输出,或者跳过文本中的模式输出
解答:
为了把BF算法分离出来,代码写复杂了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
using namespace std;
int BF2(char txt[], char pat[], int match[]) {
int i = 0; // txt指针
int j = 0; // pat指针
int k = 0; // txt中与pat匹配的次数
int txt_len = strlen(txt), pat_len = strlen(pat);
while (i <= txt_len - 1 && j <= pat_len - 1) {
if (txt[i] == pat[j] || txt[i] == pat[j] - 32 ) { // 如果文本中的字符与模式中的字符或其大写相同,则本次匹配成功
++i; // 文本指针和模式指针都前进一位
++j;
if(j == pat_len) { // 如果模式已经遍历完,则表明本轮匹配成功
match[k++] = i - pat_len; // 将本次匹配的启示位置加入match数组
j = 0; // 模式指针重新指向模式首位
}
}
else { // 当前位置元素不匹配,则本次匹配失败
i = i - j + 1; // 文本指针指向本轮匹配起始位置的下一位
j = 0; // 模式指针重新指向模式首位
}
}
return k;
}
//将输入的字符串全部元素转为小写
void capital_to_lower (char txt[]) {
for (int i = 0; txt[i] != '\0'; ++i) {
if (txt[i] >= 'A' && txt[i] <= 'Z')
txt[i] += 32;
}
}
void print(char txt[], int match[], int match_num, int pat_len) {
int i = 0; // 文本指针
int j = 0; // 匹配位置序号
int txt_len = strlen(txt); // 文本长度
if(txt_len > 0) { // 如果文本长度大于0,即如果文本不为空
if(match_num == 0) { // 如果文本中不存在模式
for(int i = 0; i <= txt_len - 1; i++) { // 遍历文本,依次输出空格以外的字符
if(txt[i] != ' ')
printf("%c", txt[i]);
}
}
else { // 如果文本中包含模式
while(i <= txt_len - 1) { // 遍历文本
if(txt[i] == ' ') { // 跳过空格
i++;
continue;
}
if(i != match[j]) { // 如果当前位置不是匹配位置
printf("%c", txt[i]); // 输出当前元素
i++; // 文本指针指向下一位
}
else { // 如果当前位置是匹配位置
i += pat_len; // 指针向前跳过文本中包含的模式
if(j < match_num - 1) // 如果还有匹配位置,则j指向下一个匹配位置
j++;
}
}
}
}
printf("\n"); // 每一次都要输出换行
}
int main () {
char pat[1000]; // 文本字符数组
char txt[1000]; // 模式字符数组
gets(pat);
capital_to_lower(pat); // 文本字符数组的元素全部转为小写
int pat_len = strlen(pat);
while(gets(txt) != NULL) {
int match[1000]; // 文本中模式出现的位置
int match_num = BF2(txt, pat, match);
print(txt, match, match_num, pat_len);
}
return 0;
}
坑:
卡在答案50好久,查了一下并回忆了一下以前出现这个错误的情况,大致判断是数组越界了。果不其然,下面部分缺了个continue。
while(i <= txt_len - 1) { // 遍历文本
if(txt[i] == ' ') { // 跳过空格
i++;
continue;
}
if(i != match[j]) { // 如果当前位置不是匹配位置
printf("%c", txt[i]); // 输出当前元素
i++; // 文本指针指向下一位
}
else { // 如果当前位置是匹配位置
i += pat_len; // 指针向前跳过文本中包含的模式
if(j < match_num - 1) // 如果还有匹配位置,则j指向下一个匹配位置
j++;
}
}
当文本以空格结尾时,第一个if跳过空格后i指向超过数组的位置,此时文本已经遍历完,不应该再访问文本字符数组,但由于没有continue,while循环继续往下走,当前位置在超过了数组,必然不是匹配位置,于是进入if,访问超过文本大小的位置,数组越界。