如何使用std :: string替换所有出现的两个字符的一个字符?

时间:2011-04-09 18:50:10

标签: c++ replace escaping stdstring

是否有一种简单的方法可以将"/"std::string的所有"\/"替换为std::string,以转义{{1}}中的所有斜杠?

6 个答案:

答案 0 :(得分:34)

完成此操作的最简单方法可能是使用boost string algorithms library

  boost::replace_all(myString, "/", "\\/");

  std::string result = boost::replace_all_copy(myString, "/", "\\/");

答案 1 :(得分:6)

答案是否定的......如果您的意思是标准库已经提供了单行程,那么就没有“简单”的方法。然而,实现该功能并不难。

首先,我认为您可能还需要将\替换为\\和其他特殊字符。在这种情况下,使用ildjarn给出的replaceAll实现会很烦人(你需要多次替换相同的字符串)。

在我看来,有许多字符串处理的情况,其中没有任何东西使用明确的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]);
}

基本上我的想法是移动字符串并在任何特殊字符之前添加额外的\字符(上面我刚刚处理了/\,但你明白了)。 已知结果长度最大为2*n,因此我预先分配它使得整个处理O(n)(replaceAll方法而不是将字符串的其余部分向右移动,使其成为为O(n ^ 2))。 即使对于像"this is a test with /slashes/ that should be /escaped/"这样的短字符串,即使只调用replaceAll一次并在escape中处理两个特殊字符,上述函数在我的PC上也更有效(速度为1.3倍)。

另请注意,此函数自然会返回一个单独的字符串而不是修改字符串(IMO是一个更好的接口),并且在时序比较中我必须为每个调用创建一个字符串,因此结果甚至会转向相等,因为这增加了不变的时间。

上述读/写方法也可以轻松扩展到更复杂的替换(例如,用>替换&gt;或用%xx编码替换不在可打印范围内的字符仍然保持良好状态大字符串的效率(只需一次通过)。

答案 2 :(得分:2)

有关如何执行此操作的示例,请参见cppreference.com std::string::replace page

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;
}

答案 3 :(得分:1)

答案 4 :(得分:1)

用另一个子字符串替换字符串中子字符串的所有出现:

#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';
}

输出:

$ 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.

答案 5 :(得分:0)

我在问题上进行了推断,制作了一个流媒体实现,让你可以逃脱各种各样的角色。

Streaming真的需要大量的饼干[1],因为否则你会陷入堆碎片/性能。此外,这允许您转义存储在几乎任何源中的字符串,如示例所示

See it Live On Coliru

#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 '\0': 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;
}

我选择了一个开关,因为它将由编译器优化。对于可动态字符的动态集合,我更喜欢某种查找(带有std :: find的向量会做,但对于大型集合,使用set :: find的std :: set将成为更好的选择。)

希望这有帮助

[1]见例如我最近遇到的这个漂亮的bug:GParted: Simplified cleanup_cursor() implementation