如何替换字符串中所有出现的字符?

发布于 2024-09-02 21:50:06 字数 60 浏览 7 评论 0原文

std::string 中将所有出现的字符替换为另一个字符的有效方法是什么?

What is the effective way to replace all occurrences of a character with another character in std::string?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

来日方长 2024-09-09 21:50:06

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 doesn't contain such function but you could use stand-alone replace function from algorithm header.

#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'
}
ヅ她的身影、若隐若现 2024-09-09 21:50:06

问题集中在 character 替换上,但是,因为我发现此页面非常有用(特别是 Konrad 的评论),我想分享这个更通用的实现,它也允许处理子字符串

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
}

希望这对其他人有帮助......

The question is centered on character replacement, but, as I found this page very useful (especially Konrad's remark), I'd like to share this more generalized implementation, which allows to deal with substrings as well:

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

Usage:

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;

Outputs:

Number_Of_Beans

XXjXugtXty

hhjhugthty


EDIT:

The above can be implemented in a more suitable way, in case performance is of your concern, by returning nothing (void) and performing the changes "in-place"; that is, by directly modifying the string argument str, passed by reference instead of by value. This would avoid an extra costly copy of the original string by overwriting it.

Code :

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

Hope this will be helpful for some others...

烟沫凡尘 2024-09-09 21:50:06

我想我也应该加入 boost 解决方案

#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 thought I'd toss in the boost solution as well:

#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, "#", "@");
何处潇湘 2024-09-09 21:50:06

想象一个大的二进制 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);
}

Imagine a large binary blob where all 0x00 bytes shall be replaced by "\1\x30" and all 0x01 bytes by "\1\x31" because the transport protocol allows no \0-bytes.

In cases where:

  • the replacing and the to-replaced string have different lengths,
  • there are many occurences of the to-replaced string within the source string and
  • the source string is large,

the provided solutions cannot be applied (because they replace only single characters) or have a performance problem, because they would call string::replace several times which generates copies of the size of the blob over and over.
(I do not know the boost solution, maybe it is OK from that perspective)

This one walks along all occurrences in the source string and builds the new string piece by piece once:

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);
}
放我走吧 2024-09-09 21:50:06

对单个字符的简单查找和替换将类似于:

s.replace(s.find("x"), 1, "y")

要对整个字符串执行此操作,简单的方法要做的事情是循环直到您的 s.find 开始返回 npos 。我想你也可以捕获 range_error 来退出循环,但这有点难看。

A simple find and replace for a single character would go something like:

s.replace(s.find("x"), 1, "y")

To do this for the whole string, the easy thing to do would be to loop until your s.find starts returning npos. I suppose you could also catch range_error to exit the loop, but that's kinda ugly.

风尘浪孓 2024-09-09 21:50:06

为了完整起见,以下是如何使用 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");
}

For completeness, here's how to do it with 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");
}
海之角 2024-09-09 21:50:06

如果您想要替换多个单个字符,并且只处理 std::string,那么此代码段可以工作,用 sReplace 替换 sHaystack 中的 sNeedle,并且 sNeedle 和 sReplace 不需要大小相同。此例程使用 while 循环来替换所有出现的位置,而不仅仅是从左到右找到的第一个位置。

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}

If you're looking to replace more than a single character, and are dealing only with std::string, then this snippet would work, replacing sNeedle in sHaystack with sReplace, and sNeedle and sReplace do not need to be the same size. This routine uses the while loop to replace all occurrences, rather than just the first one found from left to right.

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
离鸿 2024-09-09 21:50:06

正如基里尔建议的那样,要么使用替换方法,要么沿着字符串迭代独立替换每个字符。

或者,您可以根据需要执行的操作使用 find 方法或 find_first_of 。这些解决方案都无法一次性完成工作,但是通过几行额外的代码,您应该可以让它们为您工作。 :-)

As Kirill suggested, either use the replace method or iterate along the string replacing each char independently.

Alternatively you can use the find method or find_first_of depending on what you need to do. None of these solutions will do the job in one go, but with a few extra lines of code you ought to make them work for you. :-)

暗地喜欢 2024-09-09 21:50:06

老派:-)

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\

Old School :-)

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;

Result:

H:\recursos\audio\youtube\libre\falta\

扎心 2024-09-09 21:50:06

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, {
//                                                {"&", "&"},
//                                                {"<", "<"},
//                                                {">", ">"},
//                                                {"\"", """},
//                                                {"'", "'"}});

What about Abseil StrReplaceAll? From the header file:

// 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, {
//                                                {"&", "&"},
//                                                {"<", "<"},
//                                                {">", ">"},
//                                                {"\"", """},
//                                                {"'", "'"}});
千と千尋 2024-09-09 21:50:06

标准 C++ 中的单行代码:

C++20

#include <string>
#include <algorithm>
#include <iostream>

int main()
{
    std::string str{ "This is a test string." };

    std::ranges::replace(str, 'i', 'p'); // -> "Thps ps a test strpng."

    std::cout << str << std::endl;
}

演示

C++20 之前

#include <string>
#include <algorithm>
#include <iostream>

int main()
{
    std::string str{ "This is a test string." };

    std::replace(str.begin(), str.end(), 'i', 'p'); // -> "Thps ps a test strpng."

    std::cout << str << std::endl;
}

演示

A single line of code in standard C++:

C++20

#include <string>
#include <algorithm>
#include <iostream>

int main()
{
    std::string str{ "This is a test string." };

    std::ranges::replace(str, 'i', 'p'); // -> "Thps ps a test strpng."

    std::cout << str << std::endl;
}

Demo

Prior to C++20

#include <string>
#include <algorithm>
#include <iostream>

int main()
{
    std::string str{ "This is a test string." };

    std::replace(str.begin(), str.end(), 'i', 'p'); // -> "Thps ps a test strpng."

    std::cout << str << std::endl;
}

Demo

南风几经秋 2024-09-09 21:50:06
#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;
}
#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;
}
彼岸花ソ最美的依靠 2024-09-09 21:50:06

对于简单的情况,这在不使用 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

For simple situations this works pretty well without using any other library then std::string (which is already in use).

Replace all occurences of character a with character b in some_string:

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}

If the string is large or multiple calls to replace is an issue, you can apply the technique mentioned in this answer: https://stackoverflow.com/a/29752943/3622300

梦回旧景 2024-09-09 21:50:06

这是我本着最大的 DRI 精神推出的解决方案。
它将在 sHaystack 中搜索 sNeedle 并用 sReplace 替换它,
如果非 0,则为 n 次,否则所有 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;
}

here's a solution i rolled, in a maximal DRI spirit.
it will search sNeedle in sHaystack and replace it by sReplace,
nTimes if non 0, else all the sNeedle occurences.
it will not search again in the replaced text.

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;
}
回忆追雨的时光 2024-09-09 21:50:06

仅使用古老的 C 字符串函数将任意字符串替换为任意字符串怎么样?

char original[256]="First Line\nNext Line\n", dest[256]="";
char* replace_this = "\n"; // this is now a single character but could be any string
char* with_this = "\r\n"; // this is 2 characters but could be of any length

/* get the first token */
char* token = strtok(original, replace_this);

/* walk through other tokens */
while (token != NULL) {
    strcat(dest, token);
    strcat(dest, with_this);
    token = strtok(NULL, replace_this);
}

dest 现在应该有我们正在寻找的内容。

How about replace any character string with any character string using only good-old C string functions?

char original[256]="First Line\nNext Line\n", dest[256]="";
char* replace_this = "\n"; // this is now a single character but could be any string
char* with_this = "\r\n"; // this is 2 characters but could be of any length

/* get the first token */
char* token = strtok(original, replace_this);

/* walk through other tokens */
while (token != NULL) {
    strcat(dest, token);
    strcat(dest, with_this);
    token = strtok(NULL, replace_this);
}

dest should now have what we are looking for.

夕嗳→ 2024-09-09 21:50:06

这有效!我在书店应用程序中使用了类似的东西,其中库存存储在 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.

This works! I used something similar to this for a bookstore app, where the inventory was stored in a CSV (like a .dat file). But in the case of a single char, meaning the replacer is only a single char, e.g.'|', it must be in double quotes "|" in order not to throw an invalid conversion 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

Uncustomarily I am using CentOS currently, so my compiler version is below . The C++ version (g++), C++98 default:

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.
会发光的星星闪亮亮i 2024-09-09 21:50:06

这不是标准库中缺少的唯一方法,它的目的是低级别的。
此用例和许多其他用例均由通用库涵盖,例如:

QtCore & QString 有我的偏好:它支持 UTF8 并且使用更少的模板,这意味着可以理解的错误和更快的编译。它使用“q”前缀,这使得命名空间变得不必要并简化了标头。
Boost 通常会生成可怕的错误消息并降低编译时间。
POCO 似乎是一个合理的妥协。

This is not the only method missing from the standard library, it was intended be low level.
This use case and many other are covered by general libraries such as:

QtCore & QString has my preference: it supports UTF8 and uses less templates, which means understandable errors and faster compilation. It uses the "q" prefix which makes namespaces unnecessary and simplifies headers.
Boost often generates hideous error messages and slow compile time.
POCO seems to be a reasonable compromise.

眉目亦如画i 2024-09-09 21:50:06

我想我会使用 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;
}

I think I'd use std::replace_if()

A simple character-replacer (requested by OP) can be written by using standard library functions.

For an in-place version:

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

and an overload that returns a copy if the input is a const string:

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;
}
_失温 2024-09-09 21:50:06

如果您不知道是否使用答案 std::range::replacestd::replace

这是替换字符串长度 ~300 长字符串的基准。
快速基准测试
GCC 和 Clang 都有类似的结果。

在带有 -O3 的 GCC 13.2 上,它们几乎相同(std::replace:1565.638,std::range::replace:1557.231

在 Clang 16.0 上,使用 -O3 std::replace:395.697,std::range::replace:404.269

源代码:

constexpr static std::string_view TEST_STRING = "aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka ";
const char FIND = 'l';
const char REPLACED = 'q';

static void Replace(benchmark::State& state) {
  // Code inside this loop is measured repeatedly
  for (auto _ : state) {
    std::string s(TEST_STRING);
    std::replace(std::begin(s), std::end(s),FIND, REPLACED);

    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
// Register the function as a benchmark
BENCHMARK(Replace);

static void RangeReplace(benchmark::State& state) {
  // Code before the loop is not measured
  for (auto _ : state) {
    std::string s(TEST_STRING);
    std::ranges::replace(s,FIND,REPLACED);

    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
BENCHMARK(RangeReplace);


static void Baseline(benchmark::State& state) {
  // Code before the loop is not measured
  for (auto _ : state) {
    std::string s(TEST_STRING);
    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
BENCHMARK(Baseline);

旁注:
如果您有一个大于三级缓存的长字符串,需要用映射表替换(例如:a->1, b- >2...等)
最好优化时间局部性。

例如: https://quick-bench.com/q/-x3IUSk9YYL-fh0NIFSS6teT9wQ

If you don't know whether to use the answers std::range::replace or std::replace

Here's the benchmark for replacing a string length ~300 long string.
Quick benchmark
Both of GCC and Clang have similar results.

On GCC 13.2 with -O3, they are nearly the same (std::replace: 1565.638, std::range::replace: 1557.231

On Clang 16.0 with -O3 std::replace: 395.697, std::range::replace: 404.269

Source code:

constexpr static std::string_view TEST_STRING = "aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka aslkdfjl;aksjdflk;gajslkdfjaslk;dfjlkasd jflkjlkjlkjsldfka ";
const char FIND = 'l';
const char REPLACED = 'q';

static void Replace(benchmark::State& state) {
  // Code inside this loop is measured repeatedly
  for (auto _ : state) {
    std::string s(TEST_STRING);
    std::replace(std::begin(s), std::end(s),FIND, REPLACED);

    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
// Register the function as a benchmark
BENCHMARK(Replace);

static void RangeReplace(benchmark::State& state) {
  // Code before the loop is not measured
  for (auto _ : state) {
    std::string s(TEST_STRING);
    std::ranges::replace(s,FIND,REPLACED);

    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
BENCHMARK(RangeReplace);


static void Baseline(benchmark::State& state) {
  // Code before the loop is not measured
  for (auto _ : state) {
    std::string s(TEST_STRING);
    // Make sure the variable is not optimized away by compiler
    benchmark::DoNotOptimize(s);
  }
}
BENCHMARK(Baseline);

Side notes:
If you have a long string larger than L3 cache and need to replace with a mapping table (Eg: a->1, b->2...etc)
It's better to optimize temporal locality.

Eg: https://quick-bench.com/q/-x3IUSk9YYL-fh0NIFSS6teT9wQ

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文