web-dev-qa-db-ja.com

文字列内のすべての文字を置き換える方法は?

ある文字のすべての出現箇所をstd::string内の別の文字に置き換えるための効果的な方法は何ですか?

426
big-z

std::stringにはそのような関数は含まれていませんが、replaceヘッダーからスタンドアロンのalgorithm関数を使用することができます。

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

私は ブーストソリューション にも投げたいと思った。

#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, "#", "@");
120
UncleZeiv

質問はcharacter置換に集中していますが、このページが非常に便利だとわかったので(特に Konrad のコメント)、このより一般化された実装を共有したいと思います。 substringsも処理します:

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に対して直接変更を実行することにより、上記の方法をより適切な方法で実装できます引数として、by valueの代わりにbyby addressを渡しました。これにより、結果を返す間、元の文字列の無駄で高価なコピーが回避されます。それでは...

コード:

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

これが他の人にとって役立つことを願っています...

110

トランスポートプロトコルでは\ 0バイトが許されないため、すべての0x00バイトが "\ 1\x30"に、すべての0x01バイトが "\ 1\x31"に置き換えられる大きなバイナリBLOBを想像してください。

以下の場合

  • 置換文字列と置換文字列の長さが異なります。
  • ソース文字列内に置換対象文字列が多数存在する
  • ソース文字列が大きい

提供されたソリューションは適用できません(1文字のみを置き換えるため)、またはパフォーマンス上の問題があります。なぜなら、string :: replaceを何度も呼び出すため、BLOBのサイズのコピーが何度も生成されるためです。 (私はブーストソリューションを知りません、多分それはその観点から大丈夫です)

これは、ソース文字列内のすべての出現箇所に沿って進み、新しい文字列を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);
}
26
minastaros

単一の文字を単純に検索して置き換えると、次のようになります。

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

文字列全体に対してこれを行うには、s.findnposを返し始めるまでループするのが簡単です。ループを終了するためにrange_errorをキャッチすることもできると思いますが、それはちょっと醜いです。

20
T.E.D.

複数の文字を置き換えることを検討していて、std::stringのみを扱う場合は、このスニペットは機能します。sHaystackのsNeleをsReplaceに置き換えます。sNeedleとsReplaceは同じサイズである必要はありません。このルーチンは、左から右に最初に見つかったものだけではなく、whileループを使用してすべてのオカレンスを置き換えます。

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

Kirillが示唆したように、replaceメソッドを使うか、文字列に沿って各charを個別に置き換えながら繰り返します。

代わりに、あなたがする必要があるものに応じてfindメソッドまたはfind_first_ofを使うことができます。これらの解決策のどれも一度に仕事をしないでしょう、しかしあなたはそれらをあなたのために働くようにするべきであるいくつかの余分なコード行であなたはすべきです。 :-)

4
Konrad
#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;
}
3
Lloydie

単純な状況では、これは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

0
Guney Ozsan

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

古い学校 :-)

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 \

0

これはうまくいきます!私はこのようなものを本屋アプリに使いました。そこでは在庫が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.
0
oOpSgEo