字符串替换
C++ string 中有自带的replace替换函数,其替换方式有以下几种:
(http://www.cplusplus.com/reference/string/string/replace)
这几种方式都是只能针对某一个目标进行替换,不能对字符串中出现多次目标的情形进行全部替换。下面我们给出对字符串中所有目标进行替换的程序。
一、两种基本的全部替换方式
比如给定一目标字符串(以下参考自Vimer):
12212
我们将其中的“12”替换为“21”,有两种替换方式,分别为:
1)进行distinct替换,即每次替换后,对替换后面的进行替换,不考虑替换后的字符序
列;
2)每次替换后,再进行下一步替换时,考虑之前替换的字符序列;
相应的两种替换方式替换后的结果分别为:
21221
22211
两种替换方式的程序分别为:
// 字符串的两种替换方式 #include <iostream> #include <string> using namespace std; string& replace_all_distinct(string& str, const string& src, const string& des) { for (string::size_type i = 0; i != string::npos; i += des.size()) { i = str.find(src, i); if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } string& replace_all_notdistinct(string& str, const string& src, const string& des) { for (string::size_type i = 0; ; ) { i = str.find(src); // 从头开始查找 if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } int main() { string str("12212"); cout << replace_all_distinct(str, "12", "21") << endl; str = "12212"; cout << replace_all_notdistinct(str, "12", "21") << endl; system("PAUSE"); return 0; }
注意,第二种方式有可能造成死循环,比如对于12212,如果将12替换为212,那么将永远不会终止,因为对于12替换后的212,还会替换为2212、22212、222212……所以,对于这种替换方式,我们的原则是替换后的字符序列不能包含被替换的字符序列。
二、一点改进
接下来,我们做一点改进,就是指定替换的个数,我们设定一个参数,用来记录替换目标字符串的次数(参考自Mike_Zhang),这里我们可以按照从前到后的次序,也可以从后到前。具体程序如下:
// 定量替换&逆向替换 #include <iostream> #include <string> using namespace std; string& replace_all_distinct(string& str, const string& src, const string& des, int n) { int count = 0; for (string::size_type i = 0, count = 0; i != string::npos && count < n; i += des.size(), ++count) { i = str.find(src, i); if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } string& r_replace_all_distinct(string& str, const string& src, const string& des, int n) { int count = 0; for (string::size_type i = str.size()-1, count = 0; i != string::npos && count < n; --i, ++count) { i = str.rfind(src, i); if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } string& replace_all_notdistinct(string& str, const string& src, const string& des, int n) { int count = 0; for (string::size_type i = 0, count = 0; count < n; ++count) { i = str.find(src); // 从头开始查找 if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } string& r_replace_all_notdistinct(string& str, const string& src, const string& des, int n) { int count = 0; for (string::size_type i = str.size()-1, count = 0; count < n; ++count) { i = str.rfind(src); // 从尾开始查找 if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } int main() { string str("abababababab"); cout << replace_all_distinct(str, "ab", "xy", 3) << endl; str = "aababababab"; cout << replace_all_notdistinct(str, "ab", "ba", 2) << endl; str = "abababababab"; cout << r_replace_all_distinct(str, "ab", "xy", 3) << endl; str = "ababababaab"; cout << r_replace_all_notdistinct(str, "ab", "ba", 2) << endl; system("PAUSE"); return 0; }
三、批量替换
前面我们做的替换是对字符串中所有出现目标序列进行的替换,但是我们只是针对单一的目标序列。这里我们将对多个目标序列进行替换操作。我们默认多个目标序列之间不存在包含、被包含、相等等关系。
具体实现有以下两种方式:
1)针对每个待替换字符序列,顺序查找并替换。假如查找并替换依次的时间复杂度为
O(1),那么这种方式的时间复杂度为:O(N*M),其中N为待替换字符序列的个数,M为单个待替换序列出现的平均次数。
2)另一种方式是:顺序扫描一次字符串,查找最早出现那个待替换字符序列的位置,
然后进行替换,这样针对每个出现的位置会查找N*M*N次,替换N*M次,所以时
间复杂度为O(N*M*N)。
根据以上的分析,我们采用第一种替换方法:
// 逐个替换 #include <iostream> #include <string> #include <vector> using namespace std; string& replace_all_distinct(string& str, const string& src, const string& des) { for (string::size_type i = 0; i != string::npos; i += des.size()) { i = str.find(src, i); if (i != string::npos) { str.replace(i, src.size(), des); } else { break; } } return str; } string& n_replace(string& str, const vector<string>& src, const vector<string>& des) { assert(src.size() > 0 && src.size() == des.size()); for (vector<string>::size_type i = 0; i != src.size(); ++i) { replace_all_distinct(str, src[i], des[i]); } return str; } int main() { vector<string> src, des; src.push_back("+"); src.push_back("-"); src.push_back("*"); src.push_back("/"); src.push_back("("); src.push_back(")"); des.push_back(" + "); des.push_back(" - "); des.push_back(" * "); des.push_back(" / "); des.push_back(" ( "); des.push_back(" ) "); string str("1+2-3*4/5+(1/3)"); cout << n_replace(str, src, des) << endl; system("PAUSE"); return 0; }
四、总结
以上我们对字符串两种基本的替换方式做了一些总结,并对其进行了一些改进,最后针对字符串做批量替换。
通过批量替换,我们将运用到后面的针对表达式的空白符预处理,以绕开词法分析。