C++Primer 第五版 练习9.43 解答



练习9.43:编写一个函数,接受三个string参数s,oldValnewVal。使用迭代器及inserterase函数将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是参考别人的代码添加的,这是我不足的地方。 


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值