一重循环实现删除子字符串(C++)
从一个字符串里删除子串是非常常见的操作,如:
void deletestr(const char *str, const char* sub_str, char *result)
str 指向的是主串,sub_str 是子串,rersult 是处理后的结果。当str 指向 “abcdabcd”、sub_str 指向 “ab" 时,处理完成后的结果是 result 指向 “cdcd”,result 已经分配了和 str 一样长的空间。
通常我们的第一反应就是通过二重循环实现。当出现第一个与子串首字符相同的字符时,开始一个新循环来比较。
显然这个方法是容易想到的,当字符串很长或者子串出现的次数很多时,效率也就不高了,那么可不可以用一重循环来实现呢?我们仔细想想,这个问题是很好解决的。
void deletestr(const char *str, const char* sub_str, char *result) { //获得子串的长度 int sublen = 0; const char *t = sub_str; while(*t++ != '\0') { sublen++; } int pos = 0; int pp = 0; int repos = 0; // 结果子串的索引 while(*(str + pos) != '\0') { char t = *(str + pos); if(t == *(sub_str + pp)) // 重复子串起始位置 { *(result + repos) = t; repos++; if(pp < sublen - 1) // 还未完全重复 { pp++; } else if(pp == sublen - 1) // 完全重复了 { pp = 0; repos -= sublen; // 回溯下标位置 } } else{ // 不是一样的字符 *(result + repos) = t; repos++; } pos++; } *(result + repos) = '\0'; }
其实思想很容易理解,首先不管是不是重复,都复制到result指定的串中,当判断 if(pp == sublen - 1) 条件成立时,意味着出现了完全相同的子串,这时就需要将记录 result 字符长度变量 repos 减去子串长度,回到子串开始出现的位置,再开始复制,此时会覆盖掉之前记录在 result 里子串。