练习9.43:编写一个函数,接受三个string参数s,oldVal和newVal。使用迭代器及insert和erase函数将s中所有oldVal替换为newVal。测试你的程序,用它替换通用的简写形式,如,将“tho”替换为“though”,将“though”。
思路:刚开始做这道题的时候,没成想会有多难,真正写的时候,发现问题很多。最开始,期望走循环方式来标记相符的迭代器初始位置,简单说,就是找到*iter == *oldVal.begin();标记这个iter,但写到这边,才发现内部循环考虑的太多,折腾很久,放弃;思路二,树上提供了字符串substr的操作,在初始思路的基础上又走了一遍,还是没走通,其实说到底没掌握好,迭代器的位置,在一趟循环里,删除插入,迭代器位置控制不好,会造成迭代器失效。又放弃。后来参考了网上的代码,据我能找到的,多多少少都存在问题,比如找到的代码里,测试"mtho my C++ tho,Primer"时,确实能够替换,但换一个"tho th"程序僵在那了。再比如另一个找到的代码,我用的编译器(DEV下面的GCC,G++)编译不通过,iters=s.insert(iters,newValue.begin(),newValue.end()); 这句话存在问题。
想了一夜,我有了一个新的思路
1.既然在一句话里找子串那么烦,干嘛我们不借助容器的帮忙?
第一步:单词分割,将一句话里单词分割存放到一个vector<string>里。
2.肯定要走一回循环,那为什么不考虑最好的情况,和一般的情况?
第二步:a.最好情况,被分割的单词和oldVal是相同的。这时候删除和替换都是比较爽的
b.一般情况,oldVal可能是某个单词的子串,那痛苦的过程还是要经历,但这回我们是在顺序容器的一个小房间里做这件事(是不是在想别的,嘿嘿),不必考虑全局,把当前的情况考虑好就可以,只考虑一个单词的情况,剩下的交给容器,让容器傻瓜复制执行,这里必须说明参考了http://m.blog.youkuaiyun.com/blog/jierandefeng/38920947,迭代器的位置,我没控制好,因此,看了别人的代码
c.既不是a,也不是b,那还不好,让迭代器自由走,不用被抓过来处理a和b
第三步:不用说咧,写个测试用例看看,能否达到要求,话不多说,传代码
/*
*练习9.43
*日期:2015/8/6
*问题描述:练习9.43:编写一个函数,接受三个string参数s,oldVal和newVal。使用迭代器及insert和erase函数将s中所有oldVal替换为newVal。测试你的程序,用它替换通用的简写形式,如,将"tho"替换为"though",将"thru"替换为"though"。
*说明:这道题写了N遍,参考了网上的,发现基本都或多或少存在问题
*思路:1.分割单词,存入到一个容器
2.如果单词和oldVal相同,替换操作简单
3.考虑oldVal是单词子串的情况,进行替换,这里参考了别人的写法,注意迭代器的位置
*作者:Nick Feng
*邮箱:nickgreen23@163.com
*/
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
void find_replace(string s, string oldVal, string newVal)
{
if (s.empty()||oldVal.empty()||newVal.empty())
{
cout << "s or oldVal or newVal字符串为空,请检查" << endl;
return;
}
if (s.size() < oldVal.size())
{
cout << "目标字符串长度小于要查找的字符串" << endl;
return;
}
string word;
vector<string> vec;
istringstream stream(s); //利用了流进行了单词分割
{
while(stream >> word)
vec.push_back(word);
}
vector<string>::iterator it = vec.begin();
while(it != vec.end())
{
if(*it == oldVal) //最想要的情况,正好这个单词就是要匹配的
{
string::iterator iter = (*it).begin();
iter=(*it).erase(iter, iter+oldVal.size());
(*it).insert(iter,newVal.begin(),newVal.end());
}
else //比较不好的情况,在单词的子串里面找找看看
{
string::iterator iter = (*it).begin();
string::iterator oiter = oldVal.begin();
while(iter != (*it).end()) //走到一个分支
{
if(*iter == *oiter)
{
string substring = (*it).substr(iter - (*it).begin(), oldVal.size());
if(substring == oldVal)
{
unsigned offSet = iter - (*it).begin(); //这边参考 http://m.blog.youkuaiyun.com/blog/jierandefeng/38920947
iter = (*it).erase(iter,iter+oldVal.size());
(*it).insert(iter,newVal.begin(),newVal.end());
iter = (*it).begin() + offSet + newVal.size() - 1;
}
}
++iter;
}
}
++it;
}
for(auto i = 0; i != vec.size(); ++i)
cout << vec[i] << " ";
cout << endl;
}
int main()
{
string s = "tho thogll thru athru AthruB";
cout << s << endl;
cout << "through replace tho" << endl;
find_replace(s,"tho","though");
cout << endl;
cout << s << endl;
string str = "thru th";
cout << "through replace thru" << endl;
find_replace(s,"thru","through");
cout << endl;
return 0;
}
我的程序肯定存在不足,希望看到的朋友,不要喷,对于参考的那些网址上的代码,首先很感谢,我所反映的问题也不一定都是对的,可能我也有疏忽的地方,最后关于写的程序,供大家参考,写出自己的思路,本人比较笨,所以,这次折腾了很久,基本做到符合题目的要求,其中还有可以改进的地方,比如函数可以返回一个string类型,懒得改了,这里分享自己的思路,抛砖引玉,希望大家共同学习,共同探讨,勿喷哈。最后想说的是,写程序的时候,尽可能要考虑前面,函数里面的前两个if是参考别人的代码添加的,这是我不足的地方。