【发布时间】:2011-02-23 04:57:48
【问题描述】:
用std::string中的另一个字符替换所有出现的字符的有效方法是什么?
【问题讨论】:
-
当谈到这种“高级”功能时,stdlib 似乎很糟糕。当你开始寻找丢失的东西时,最好使用 QString 或通用库。
标签: c++ algorithm str-replace stdstring
用std::string中的另一个字符替换所有出现的字符的有效方法是什么?
【问题讨论】:
标签: c++ algorithm str-replace stdstring
std::string 不包含此类函数,但您可以使用来自 algorithm 标头的独立 replace 函数。
#include <algorithm>
#include <string>
void some_func() {
std::string s = "example string";
std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
【讨论】:
std::string 是一个容器,专门设计用于处理字符序列。 link
std::string::replace() 而不是std::replace() 所发生的事情! 'x' (char) 被隐式转换为 size_t [值 120],因此整个字符串或部分字符串将被 120 个 'y' 副本填充。
正如基里尔建议的那样,要么使用替换方法,要么沿着字符串迭代,独立替换每个字符。
或者,您可以根据需要使用find 方法或find_first_of。这些解决方案都不会一次性完成这项工作,但是您应该通过几行额外的代码让它们为您工作。 :-)
【讨论】:
单个字符的简单查找和替换如下所示:
s.replace(s.find("x"), 1, "y")
要对整个字符串执行此操作,最简单的方法是循环直到您的s.find 开始返回npos。我想你也可以抓住range_error 退出循环,但这有点难看。
【讨论】:
{ 字符。我不知道什么是“双括号”。也许你有某种字体问题?
我想我也会扔boost solution:
#include <boost/algorithm/string/replace.hpp>
// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");
// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");
【讨论】:
-I 标志,以便它可以在您的系统上找到 Boost 库。也许您甚至需要先安装它。
问题集中在character 替换上,但是,由于我发现这个页面非常有用(尤其是Konrad 的评论),我想分享这个更通用的实现,它允许处理@987654323 @还有:
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
用法:
std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;
输出:
Number_Of_Beans
XXjXugtXty
hhjhugthty
编辑:
以上可以以更合适的方式实现,如果您关心性能,则不返回任何内容 (void) 并直接对作为参数给出的字符串 str 执行更改,传递 按地址,而不是按值。这将避免原始字符串的无用且昂贵的副本,同时返回结果。你的电话,然后...
代码:
static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
// Same inner code...
// No return statement
}
希望这对其他人有所帮助...
【讨论】:
from字符串是否为空,否则会出现死循环。
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
int len, loop=0;
string nword="", let;
len=word.length();
len--;
while(loop<=len){
let=word.substr(loop, 1);
if(let==target){
nword=nword+replacement;
}else{
nword=nword+let;
}
loop++;
}
return nword;
}
//Main..
int main() {
string word;
cout<<"Enter Word: ";
cin>>word;
cout<<replace(word, "x", "y")<<endl;
return 0;
}
【讨论】:
word很长,调用函数时可能会有很多开销。您可以通过传递 word、target 和 replacement 作为 const 引用来优化它。
想象一个大型二进制 blob,其中所有 0x00 字节都应替换为“\1\x30”,所有 0x01 字节应替换为“\1\x31”,因为传输协议不允许使用 \0 字节。
在以下情况下:
所提供的解决方案无法应用(因为它们仅替换单个字符)或存在性能问题,因为它们会调用 string::replace 多次,这会一遍又一遍地生成 blob 大小的副本。 (不知道boost的方案,从那个角度来说可能还可以)
这个遍历源字符串中的所有出现并逐段构建新字符串一次:
void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
std::string newString;
newString.reserve(source.length()); // avoids a few memory allocations
std::string::size_type lastPos = 0;
std::string::size_type findPos;
while(std::string::npos != (findPos = source.find(from, lastPos)))
{
newString.append(source, lastPos, findPos - lastPos);
newString += to;
lastPos = findPos + from.length();
}
// Care for the rest after last occurrence
newString += source.substr(lastPos);
source.swap(newString);
}
【讨论】:
newString.append(source, lastPos, source.length() - lastPos); 而不是newString += source.substr(lastPos); 以避免创建临时字符串[正如substr() 所做的那样]。 (我无法编辑此答案,因为建议的编辑队列已满。)
如果您要替换多个字符,并且只处理 std::string,那么这个 sn-p 将起作用,将 sHaystack 中的 sNeedle 替换为 sReplace,并且 sNeedle 和 sReplace 不需要是大小相同。此例程使用 while 循环替换所有匹配项,而不仅仅是从左到右找到的第一个匹配项。
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
【讨论】:
find 呼叫。考虑将该结果作为临时变量。
这行得通!我在书店应用程序中使用了与此类似的东西,其中库存存储在 CSV(如 .dat 文件)中。但在单字符的情况下,意味着替换器只是单字符,例如'|',它必须用双引号“|”为了不抛出无效的转换 const char。
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0; // for the number of occurences.
// final hold variable of corrected word up to the npos=j
string holdWord = "";
// a temp var in order to replace 0 to new npos
string holdTemp = "";
// a csv for a an entry in a book store
string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";
// j = npos
for (int j = 0; j < holdLetter.length(); j++) {
if (holdLetter[j] == ',') {
if ( count == 0 )
{
holdWord = holdLetter.replace(j, 1, " | ");
}
else {
string holdTemp1 = holdLetter.replace(j, 1, " | ");
// since replacement is three positions in length,
// must replace new replacement's 0 to npos-3, with
// the 0 to npos - 3 of the old replacement
holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3);
holdWord = "";
holdWord = holdTemp;
}
holdTemp = "";
count++;
}
}
cout << holdWord << endl;
return 0;
}
// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85
不习惯我目前使用的是 CentOS,所以我的编译器版本低于 . C++版本(g++),C++98默认:
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
【讨论】:
如果你愿意使用std::strings,你可以按原样使用这个示例应用程序的strsub函数,或者如果你希望它采用不同的类型或一组参数来大致实现相同的目标。基本上,它使用std::string 的属性和功能来快速擦除匹配的字符集,并直接在std::string 中插入所需的字符。每次执行此替换操作时,如果仍然可以找到要替换的匹配字符,则偏移量会更新,如果由于没有其他要替换的内容而无法替换,则返回上次更新时的字符串状态。
#include <iostream>
#include <string>
std::string strsub(std::string stringToModify,
std::string charsToReplace,
std::string replacementChars);
int main()
{
std::string silly_typos = "annoiiyyyng syyyllii tiipos.";
std::cout << "Look at these " << silly_typos << std::endl;
silly_typos = strsub(silly_typos, "yyy", "i");
std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
silly_typos = strsub(silly_typos, "ii", "y");
std::cout << "There, no more " << silly_typos << std::endl;
return 0;
}
std::string strsub(std::string stringToModify,
std::string charsToReplace,
std::string replacementChars)
{
std::string this_string = stringToModify;
std::size_t this_occurrence = this_string.find(charsToReplace);
while (this_occurrence != std::string::npos)
{
this_string.erase(this_occurrence, charsToReplace.size());
this_string.insert(this_occurrence, replacementChars);
this_occurrence = this_string.find(charsToReplace,
this_occurrence + replacementChars.size());
}
return this_string;
}
如果您不想依赖使用 std::strings 作为参数来传递 C 风格的字符串,您可以在下面查看更新后的示例:
#include <iostream>
#include <string>
std::string strsub(const char * stringToModify,
const char * charsToReplace,
const char * replacementChars,
uint64_t sizeOfCharsToReplace,
uint64_t sizeOfReplacementChars);
int main()
{
std::string silly_typos = "annoiiyyyng syyyllii tiipos.";
std::cout << "Look at these " << silly_typos << std::endl;
silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);
std::cout << "There, no more " << silly_typos << std::endl;
return 0;
}
std::string strsub(const char * stringToModify,
const char * charsToReplace,
const char * replacementChars,
uint64_t sizeOfCharsToReplace,
uint64_t sizeOfReplacementChars)
{
std::string this_string = stringToModify;
std::size_t this_occurrence = this_string.find(charsToReplace);
while (this_occurrence != std::string::npos)
{
this_string.erase(this_occurrence, sizeOfCharsToReplace);
this_string.insert(this_occurrence, replacementChars);
this_occurrence = this_string.find(charsToReplace,
this_occurrence + sizeOfReplacementChars);
}
return this_string;
}
【讨论】:
对于简单的情况,这在不使用任何其他库的情况下效果很好,然后是 std::string(已经在使用)。
将some_string中所有出现的字符a替换为字符b:
for (size_t i = 0; i < some_string.size(); ++i) {
if (some_string[i] == 'a') {
some_string.replace(i, 1, "b");
}
}
如果字符串很大或多次调用替换是一个问题,您可以应用此答案中提到的技术:https://stackoverflow.com/a/29752943/3622300
【讨论】:
老派 :-)
std::string str = "H:/recursos/audio/youtube/libre/falta/";
for (int i = 0; i < str.size(); i++) {
if (str[i] == '/') {
str[i] = '\\';
}
}
std::cout << str;
结果:
H:\recursos\audio\youtube\libre\falta\
【讨论】:
Abseil StrReplaceAll 呢?从头文件:
// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
// {"&", "&"},
// {"<", "<"},
// {">", ">"},
// {"\"", """},
// {"'", "'"}});
【讨论】:
这是我以最大 DRI 精神推出的解决方案。 它将在 sHaystack 中搜索 sNeedle 并将其替换为 sReplace, nTimes 如果非 0,否则所有 sNeedle 出现。 它不会在替换的文本中再次搜索。
std::string str_replace(
std::string sHaystack, std::string sNeedle, std::string sReplace,
size_t nTimes=0)
{
size_t found = 0, pos = 0, c = 0;
size_t len = sNeedle.size();
size_t replen = sReplace.size();
std::string input(sHaystack);
do {
found = input.find(sNeedle, pos);
if (found == std::string::npos) {
break;
}
input.replace(found, len, sReplace);
pos = found + replen;
++c;
} while(!nTimes || c < nTimes);
return input;
}
【讨论】:
为了完整起见,下面是使用std::regex 的方法。
#include <regex>
#include <string>
int main()
{
const std::string s = "example string";
const std::string r = std::regex_replace(s, std::regex("x"), "y");
}
【讨论】:
我想我会使用std::replace_if()
可以使用标准库函数编写一个简单的字符替换器(由 OP 请求)。
对于就地版本:
#include <string>
#include <algorithm>
void replace_char(std::string& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::replace_if(std::begin(in), std::end(in),
[&srch](std::string::value_type v) { return v==srch; },
repl);
return;
}
如果输入是const 字符串,则返回一个副本的重载:
std::string replace_char(std::string const& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::string result{ in };
replace_char(result, srch, repl);
return result;
}
【讨论】: