C++ 如何使用 std::string 用两个字符替换所有出现的一个字符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5607085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to replace all occurrences of one character with two characters using std::string?
提问by WilliamKF
Is there a nice simple way to replace all occurrences of "/"
in a std::string
with "\/"
to escape all the slashes in a std::string
?
是否有一个很好的简单的方法,以取代所有出现"/"
在std::string
与"\/"
逃脱的所有斜线std::string
?
回答by UncleBens
Probably the simplest way to get this done is with boost string algorithms library.
完成这项工作的最简单方法可能是使用boost 字符串算法库。
boost::replace_all(myString, "/", "\/");
std::string result = boost::replace_all_copy(myString, "/", "\/");
回答by 6502
The answer is no... there is no "easy" way if you mean an one-liner already provided by the standard library. However it's not hard to implement that function.
答案是否定的……如果您的意思是标准库已经提供了单行程序,则没有“简单”的方法。然而,实现该功能并不难。
First of all I think that probably you will also need to replace \
with \\
and other special characters. In this case using the replaceAll
implementation given by ildjarn is going to be annoying (you'll need to replace the same string several times).
首先,我认为您可能还需要替换\
为\\
和其他特殊字符。在这种情况下,使用replaceAll
ildjarn 给出的实现会很烦人(您需要多次替换相同的字符串)。
In my opinion there are many cases of string processing where nothing beats using an explicit char *
approach. In this specific case however probably just using an index is fine:
在我看来,有很多字符串处理的情况,没有什么比使用显式char *
方法更好的了。但是在这种特定情况下,可能只使用索引就可以了:
std::string escape(const std::string& s)
{
int n = s.size(), wp = 0;
std::vector<char> result(n*2);
for (int i=0; i<n; i++)
{
if (s[i] == '/' || s[i] == '\')
result[wp++] = '\';
result[wp++] = s[i];
}
return std::string(&result[0], &result[wp]);
}
Basically the idea is to move over the string and adding an extra \
character before any special character (in the above I just handled /
and \
, but you get the idea).
The result is known to be at maximum 2*n
in lenght, so I preallocate it making the whole processing O(n) (the replaceAll
approach instead keeps moving the rest of the string to the right, making it O(n^2)).
Even for short strings like "this is a test with /slashes/ that should be /escaped/"
the above function is on my PC more efficient (1.3x in speed) even if calling replaceAll
just once and handling instead two special chars in escape
.
基本上这个想法是在字符串上移动并\
在任何特殊字符之前添加一个额外的字符(在上面我刚刚处理了/
and \
,但你明白了)。已知结果的2*n
长度最大,所以我预分配它使整个处理 O(n)(该replaceAll
方法反而不断将字符串的其余部分向右移动,使其成为 O(n^2))。即使对于像"this is a test with /slashes/ that should be /escaped/"
上述函数这样的短字符串,即使replaceAll
只调用一次并在escape
.
Note also that this function naturally returns a separate string instead of modifying the string in place (IMO a better interface) and in the timing comparison I had to create a string for each call so the results are even shifted toward equality because of that added constant time.
另请注意,此函数自然会返回一个单独的字符串,而不是就地修改字符串(IMO 一个更好的接口),并且在时间比较中,我必须为每个调用创建一个字符串,因此由于添加了常量,结果甚至会向相等方向移动时间。
The above read/write approach can also be easily extended to more complex substitutions (e.g. replacing >
with >
or characters not in printable range with %xx
encoding) still maintaining a good efficiency for big strings (just one pass).
上述读/写的方法也可以容易地扩展到更复杂的取代(例如替换>
用>
或字符不在可打印范围%xx
编码)仍维持为大字符串(仅一个道次)以良好的效率。
回答by ildjarn
An example on how to do this is given on the cppreference.com std::string::replace
page:
cppreference.comstd::string::replace
页面上给出了如何执行此操作的示例:
std::string& replaceAll(std::string& context, std::string const& from, std::string const& to)
{
std::size_t lookHere = 0;
std::size_t foundHere;
while((foundHere = context.find(from, lookHere)) != std::string::npos)
{
context.replace(foundHere, from.size(), to);
lookHere = foundHere + to.size();
}
return context;
}
回答by Dr McKay
回答by Christophe Saugé
To replace all the occurences of a sub-string in a string by another sub-string:
用另一个子字符串替换一个字符串中所有出现的子字符串:
#include <iostream>
void replace_all(std::string& input, const std::string& from, const std::string& to) {
size_t pos = 0;
while ((pos = input.find(from, pos)) != std::string::npos) {
input.replace(pos, from.size(), to);
pos += to.size();
}
}
int main() {
std::string str("i am a geek/nerd/crazy person.");
replace_all(str, "/", "\/");
std::cout << str << '\n';
}
Output:
输出:
$ g++-6.1.0 -std=c++17 -g -Og -Werror -Wall -Wextra -pedantic -Wold-style-cast -Wnon-virtual-dtor -Wshadow -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wmisleading-indentation -fsanitize=address,leak,undefined; ./a.out
i am a geek\/nerd\/crazy person.
回答by sehe
I extrapolated on the question, to make a streaming implementation to allows you to escape a variety of characters.
我对这个问题进行了推断,进行流式实现以允许您转义各种字符。
Streaming really takes the biscuit for large volumes[1], because you will get in heap fragmentation/performance hell otherwise. Also, this allows you to escape strings stored in just about any source, as the samples do show
流式传输确实需要大容量 [1] 的饼干,因为否则您将陷入堆碎片/性能地狱。此外,这允许您转义存储在几乎任何来源中的字符串,如示例所示
#include <iostream>
#include <iterator>
#include <set>
#include <sstream>
#include <string>
template <class _II, class _OI>
static _OI escapeSomeChars(const _II inIt, const _II endIt, _OI outIt)
{
for (_II it=inIt; it!=endIt; ++it)
switch (*it)
{
case '##代码##': outIt++ = '\'; outIt++ = '0'; break;
case '\n': outIt++ = '\'; outIt++ = 'n'; break;
case '\':
case '"' :
case '$' :
case '/' : outIt++ = '\';
default : outIt++ = *it;
}
return outIt;
}
static std::string escapeSomeChars(const std::string& input)
{
std::ostringstream os;
escapeSomeChars(input.begin(), input.end(), std::ostream_iterator<char>(os));
return os.str();
}
namespace /*anon*/ {
struct rawchar { // helper - see e.g. http://bytes.com/topic/c/answers/436124-copy-istream_iterator-question
char _c; rawchar(char c=0) : _c(c) {}
operator const char&() const { return _c; }
friend std::istream& operator>>(std::istream& is, rawchar& out) { return is.get(out._c); }
};
}
int main()
{
static const char data[] = "\"I will \$one day \have \all \\my slash\es escaped, much \like\ in the source!\n\"";
// use the overload for std::string
std::cout << escapeSomeChars(data);
std::cout << std::endl;
// streaming in & out:
std::istringstream is(data);
escapeSomeChars(std::istream_iterator<rawchar>(is), std::istream_iterator<rawchar>(), std::ostream_iterator<char>(std::cout));
std::cout << std::endl;
// but you don't need an istream, you can use any STL iterator range
escapeSomeChars(data, data+sizeof(data)/sizeof(data[0]), std::ostream_iterator<char>(std::cout));
std::cout << std::endl;
// but any source and target will do:
std::string asstring(data);
std::set<char> chars(asstring.begin(), asstring.end());
asstring.clear();
escapeSomeChars(chars.begin(), chars.end(), std::back_inserter(asstring));
std::cout << "Unique characters in data: '" << asstring << "', but properly escaped!" << std::endl;
return 0;
}
I chose a switch, because it will be optimized by the compiler. For dynamic sets of escapable characters, I'd prefer some kind of lookup (a vector with std::find would do, although for large sets a std::set with set::find would become the better choice).
我选择了一个开关,因为它会被编译器优化。对于可转义字符的动态集,我更喜欢某种查找(带有 std::find 的向量可以,但对于大型集,带有 set::find 的 std::set 将成为更好的选择)。
Hope this helps
希望这可以帮助
[1] see e.g. this beautiful bug I recently encountered: GParted: Simplified cleanup_cursor() implementation
[1] 参见例如我最近遇到的这个漂亮的错误:GParted: Simplified cleanup_cursor() implementation