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


回答:


742

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

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

6
std::stringあるコンテナ特に文字のシーケンスで動作するように設計されています。リンク
キリルV.リヤドビンスキー

164
残念ながら、これにより1つの文字のみを別の文字に置き換えることができます。charをそれ以上の文字で(つまり、文字列で)置き換えることはできません。より多くの文字で検索置換を行う方法はありますか?
SasQ 2012

6
@Kirill V. Lyadvinskyどうすれば発生を削除したいだけなのか
SIFE

4
@ KirillV.Lyadvinsky:このメソッドを使用してすべてのxをyに置き換えると、元の文字列が何であっても、結果は長いy文字列になります。何が問題だと思いますか。(コードはあなたが書いたものとまったく同じです)
超越

6
@Transcendent:これはと何が起こるかを正確であるstd::string::replace()代わりにstd::replace()!'x'(char)は暗黙的にsize_t[値120]にキャストされるため、文字列全体またはその一部が120の 'y'のコピーで埋められます。
IBue

127

私もブーストソリューションを投げると思いました:

#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、システムのBoostライブラリを見つけるために、コンパイラのいくつかのフラグがありません。おそらく最初にそれをインストールする必要さえあるでしょう。
Martin Ueding

上記はstd libに付属しているため、より効果的です。すべてはboostライブラリを使用し
ません

122

質問は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引数として指定された文字列に対して、値ではなくアドレスで渡される変更を直接実行します。これにより、結果を返す際に、元の文字列の無駄でコストのかかるコピーを回避できます。あなたの電話、それから...

コード:

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

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


4
これは、ソース文字列が大きく、置換される文字列が多数ある場合に、パフォーマンスの問題があります。string :: replace()は何度も呼び出されるため、多くの文字列がコピーされます。その問題に対処する私の解決策を参照してください。
minastaros

1
先にピックするNit:アドレスによって => 参照によって。アドレスであるかどうかは、実装の詳細です。
Max Truxa

1
from文字列が空かどうかを実際に確認する必要があります。そうしないと、無限ループが発生します。
初心者は

34

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

以下の場合:

  • 置換後の文字列と置換後の文字列の長さが異なります。
  • ソース文字列内で置換後の文字列が多数出現し、
  • ソース文字列が大きい、

提供されたソリューションは適用できません(単一の文字のみを置換するため)。また、string :: replaceを数回呼び出し、blobのサイズのコピーを繰り返し生成するため、パフォーマンスの問題があります。(私はブーストソリューションを知りません、おそらくその観点からは大丈夫です)

この1は、ソース文字列内のすべての出現に沿って歩くと、作品によって、新しい文字列ピース構築し、一度に

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

これは、STLのみに基づいて構築された、ここでの最良のソリューションです。どこでも簡単に使用できるカスタム関数をドロップする場合は、この関数にします。
ロジャーサンダース

21

単一の文字の単純な検索と置換は、次のようになります。

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

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


7
置換する文字数が文字列の長さに比べて少ない場合、これはおそらく適切な解決策ですが、適切にスケーリングされません。元の文字列内で置き換える必要のある文字の割合が増えると、このメソッドはO(N ^ 2)に近づきます。
および

7
本当です。私の一般的な哲学は、非効率が実際の問題を引き起こしているような時まで、簡単な(書き込みと読み取り)ことを行うことです。O(N ** 2)が重要である不自然な文字列が存在する状況もありますが、私の文字列は1K以下です。
TED

3
...言われているように、私はキリルの方法の方が好きです(すでに投票していました)。
TEDの

「x」が見つからない場合はどうなりますか?また、なぜ二重ブレースを使用しているのですか?
Prasath Govind

@PrasathGovind-必要な呼び出しを表示していました(したがって、「何か」のように)。重要ですが、適切なエラー処理などのあいまいな詳細は、読者への課題として残されました。「二重ブレース」に関しては、それらが何であるか、またはあなたが何について話しているのか、私にはわかりません。私にとって「ブレース」は{キャラクターです。「ダブルブレース」とは何なのかわかりません。おそらくフォントの問題があるのでしょうか?
TED 2015

6

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

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

これはO(n ^)です。O(n)時間でそれを行うことができます。
Changming Sun

3
@ChangmingSunどのO(n)ソリューションを意味しますか?
habakuk 2017年

2
kNeedleがたまたまsReplaceのサブストリングである場合、これは無限ループになります。
プライドアウト

さらに、find2回の呼び出しがあります。その結果を一時変数にすることを検討してください。
Luc Bloom、

4

Kirillが提案したように、replaceメソッドを使用するか、文字列に沿って反復して、各文字を個別に置き換えます。

または、findメソッドを使用するfind_first_ofか、必要な操作に応じて使用できます。これらのソリューションはどれも一度に機能しませんが、コードを数行追加するだけで機能するはずです。:-)


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

wordが長い場合、関数の呼び出し中に多くのオーバーヘッドが発生する可能性があります。あなたは渡すことで、これを最適化することができwordtargetreplacementのconst参照として。
TrebledJ

2

何についての懸垂下降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, {
//                                                {"&", "&amp;"},
//                                                {"<", "&lt;"},
//                                                {">", "&gt;"},
//                                                {"\"", "&quot;"},
//                                                {"'", "&#39;"}});

1

古い学校 :-)

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

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(すでに使用されています)。

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

これが、最大限のDRI精神の中で私が展開したソリューションです。sHaystackでsNeedleを検索し、それをsReplaceで置き換えます。0以外の場合はnTimes、それ以外の場合はすべての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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.