如何在标准字符串中搜索/查找和替换?


Answers:


75

为什么不实施自己的替换?

void myReplace(std::string& str,
               const std::string& oldStr,
               const std::string& newStr)
{
  std::string::size_type pos = 0u;
  while((pos = str.find(oldStr, pos)) != std::string::npos){
     str.replace(pos, oldStr.length(), newStr);
     pos += newStr.length();
  }
}

3
您在这里对“ replace”的所有调用都使内存有些混乱:如果从“ ooooooo ... o”中删除“ o”,则复杂度将为n²。我想可以做得更好,但是这种解决方案具有易于理解的优点。
Zonko

1
为什么这不是实际的for循环,而不是混淆的for循环?
Shirik 2012年

我习惯于采用“最少惊喜”原则。大多数情况下,for循环用于简单的索引增量。根据我的说法,这里的while循环更加清晰。
伊夫·鲍美斯

1
@aldo作为一般规则,最好避免复杂性,例如,使用其他答复中提到的regex。但是根据您的需要,您可能需要控制项目的依赖性。可以满足您实际需要的一点代码片段有时会更好。
伊夫·鲍美斯

158
#include <boost/algorithm/string.hpp> // include Boost, a C++ library
...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target, "foo", "bar");

这是关于replace_all 的官方文档


1
请注意,您不必为模式和替换显式创建std :: string:boost :: replace_all(target,“ foo”,“ bar”);
Alexis Wilke

4
+1,但需注意:replace_all对于升压大于1.43的版本,对于低于12.3的任何版本,将进行段错误
Brian Vandenberg

3
boost大大增加了嵌入式设备上的编译时间。甚至是ARMv7四核。2分钟内可编译100行代码,而2秒内无需增强。
Piotr Kula 2015年

4
@ppumkin:这意味着您的编译器(或构建设置,或其他任何东西)很糟糕,而不是与目标体系结构无关的目标体系结构。
Daniel Kamil Kozar

如果您的编译器支持预编译头,则强烈建议在使用boost时使用它。确实可以节省时间。
阿列克谢·奥梅利琴科

33

在C ++ 11中,您可以通过调用 regex_replace

#include <string>
#include <regex>

using std::string;

string do_replace( string const & in, string const & from, string const & to )
{
  return std::regex_replace( in, std::regex(from), to );
}

string test = "Remove all spaces";
std::cout << do_replace(test, " ", "") << std::endl;

输出:

Removeallspaces

谢谢,非常易于使用和记住!
朱利安·德克莱克

还请注意,这from可以是一个正则表达式-因此,如果需要,您可以使用更复杂的匹配条件。我看不到的是如何在应用某种形式的正则表达式解析的情况下执行此操作-而是仅使用from字符的直接解释。
布伦特·布拉德本

这可能需要最新的编译器。它可以在gcc 5.0上工作,但是在gcc 4.8.4上却遇到了一些麻烦。
布伦特·布拉德本

@nobar,是的,如果我没记错的话,4.8.x中的正则表达式支持还不完善。此外,您还可以进行更复杂的搜索,但是您会受到时间上的惩罚……它将比其他更直接的搜索和替换功能要慢。
亚历克西斯·威尔克

2
请注意,这仅适用于非常基本的字母数字字符,而无需根据字符串类型进行大量预处理就没有其他用途。我还没有发现基于通用正则表达式的字符串替换。
Piyush Soni

17

为什么不返回修改后的字符串?

std::string ReplaceString(std::string subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
    return subject;
}

如果需要性能,下面是一个优化的函数,它可以修改输入字符串,但不会创建该字符串的副本:

void ReplaceStringInPlace(std::string& subject, const std::string& search,
                          const std::string& replace) {
    size_t pos = 0;
    while((pos = subject.find(search, pos)) != std::string::npos) {
         subject.replace(pos, search.length(), replace);
         pos += replace.length();
    }
}

测试:

std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;

std::cout << "ReplaceString() return value: " 
          << ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not changed: " 
          << input << std::endl;

ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: " 
          << input << std::endl;

输出:

Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def

6

我的模板化内联就地查找和替换:

template<class T>
int inline findAndReplace(T& source, const T& find, const T& replace)
{
    int num=0;
    typename T::size_t fLen = find.size();
    typename T::size_t rLen = replace.size();
    for (T::size_t pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
    {
        num++;
        source.replace(pos, fLen, replace);
    }
    return num;
}

它返回一个被替换的项目数的计数(如果您想连续运行它,则使用它,等等)。要使用它:

std::string str = "one two three";
int n = findAndReplace(str, "one", "1");

4
我在GCC上尝试了此示例,但无法编译-它不喜欢使用T :: size_t。用类型名T :: size_type替换T :: size_t可解决此问题。
Andrew Wyatt

3

最简单的方法(提供接近您所写内容的方法)是使用Boost.Regex,特别是regex_replace

std :: string内置了find()和replace()方法,但是它们处理起来比较麻烦,因为它们需要处理索引和字符串长度。


3
还有一些助推字符串算法,包括replace_all(对于这种简单的替换,正则表达式可能有点笨重)。
UncleBens

3

我相信这会起作用。它使用const char *作为参数。

//params find and replace cannot be NULL
void FindAndReplace( std::string& source, const char* find, const char* replace )
{
   //ASSERT(find != NULL);
   //ASSERT(replace != NULL);
   size_t findLen = strlen(find);
   size_t replaceLen = strlen(replace);
   size_t pos = 0;

   //search for the next occurrence of find within source
   while ((pos = source.find(find, pos)) != std::string::npos)
   {
      //replace the found string with the replacement
      source.replace( pos, findLen, replace );

      //the next line keeps you from searching your replace string, 
      //so your could replace "hello" with "hello world" 
      //and not have it blow chunks.
      pos += replaceLen; 
   }
}

给定size_type一个字符串是unsigned,您>=在循环条件中的检查将始终为true。您必须在std::string::npos那里使用。
帕维尔·米纳夫2009年

size_type不是未签名的。它在许多平台上都是未签名的,但不是全部。
艾伦(Alan)2009年

12
为什么这不是std :: string的一部分?编程领域中是否还有其他不提供“查找并替换”操作的严肃的String类?当然,它比拥有两个迭代器并希望替换它们之间的文本更常见??有时std :: string感觉就像是一辆带有可调光谱挡风玻璃的汽车,但却无法滚下驾驶员的窗户。
Spike0xff

@ Spike0xff提升有roll_down_window
ta.speot.is

1
@gustafr:我的错。我在较旧的编译器未正确定义size_t的系统上工作。
艾伦(Alan)

1
// Replace all occurrences of searchStr in str with replacer
// Each match is replaced only once to prevent an infinite loop
// The algorithm iterates once over the input and only concatenates 
// to the output, so it should be reasonably efficient
std::string replace(const std::string& str, const std::string& searchStr, 
    const std::string& replacer)
{
    // Prevent an infinite loop if the input is empty
    if (searchStr == "") {
        return str;
    }

    std::string result = "";
    size_t pos = 0;
    size_t pos2 = str.find(searchStr, pos);

    while (pos2 != std::string::npos) {
        result += str.substr(pos, pos2-pos) + replacer;
        pos = pos2 + searchStr.length();
        pos2 = str.find(searchStr, pos);
    }

    result += str.substr(pos, str.length()-pos);
    return result;
}

1
我们只需要从最后一个匹配中搜索新匹配,这就是为什么算法会仔细跟踪pos中的最后一个匹配的原因。pos2始终存储下一个匹配项,因此我们将pos和pos2之间的字符串连接到结果,然后将pos和pos2进行前进。如果找不到其他匹配项,我们将字符串的其余部分连接起来得到结果。
比约恩·甘斯特(BjörnGanster)

1
#include <string>

using std::string;

void myReplace(string& str,
               const string& oldStr,
               const string& newStr) {
  if (oldStr.empty()) {
    return;
  }

  for (size_t pos = 0; (pos = str.find(oldStr, pos)) != string::npos;) {
    str.replace(pos, oldStr.length(), newStr);
    pos += newStr.length();
  }
}

检查oldStr是否为空很重要。如果由于某种原因该参数为空,则将陷入无限循环。

但是,如果可以的话,请使用久经考验的C ++ 11或Boost解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.