ある文字のすべての出現箇所を別の文字に置き換える効果的な方法は何std::string
ですか?
16 に答える
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'
}
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
}
これが他の人にも役立つことを願っています...
ブーストソリューションも入れたいと思いました:
#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, "#", "@");
トランスポートプロトコルでは\0バイトが許可されていないため、すべての0x00バイトが「\ 1 \ x30」に置き換えられ、すべての0x01バイトが「\ 1\x31」に置き換えられる大きなバイナリブロブを想像してみてください。
次の場合:
- 置換する文字列と置換する文字列の長さが異なります。
- ソース文字列内で置換される文字列が多数発生し、
- ソース文字列が大きい、
提供されたソリューションは適用できません(単一の文字のみを置き換えるため)、またはパフォーマンスの問題があります。これは、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);
}
単一の文字の単純な検索と置換は、次のようになります。
s.replace(s.find("x"), 1, "y")
s.find
文字列全体に対してこれを行うには、簡単に実行できるのは、戻り始めるまでループすることnpos
です。range_error
ループを終了するためにキャッチすることもできると思いますが、それはちょっと醜いです。
複数の文字を置き換える場合で、のみを処理している場合はstd::string
、このスニペットが機能し、sHaystackのsNeedleをsReplaceに置き換えます。また、sNeedleとsReplaceは同じサイズである必要はありません。このルーチンは、左から右に最初に見つかったものだけでなく、whileループを使用してすべてのオカレンスを置き換えます。
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
完全を期すために、を使用してそれを行う方法を次に示します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");
}
Kirillが提案したように、replaceメソッドを使用するか、文字列に沿って繰り返し、各文字を個別に置き換えます。
find
または、この方法を使用するfind_first_of
か、必要に応じて実行することもできます。これらのソリューションはどれも一度に機能しませんが、コードを数行追加するだけで、それらを機能させることができます。:-)
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, {
// {"&", "&"},
// {"<", "<"},
// {">", ">"},
// {"\"", """},
// {"'", "'"}});
#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;
}
古い学校 :-)
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 \
単純な状況では、これは他のライブラリを使用せずに、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
これが、最大限の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;
}
私が使うと思います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;
}
これはうまくいきます!在庫がCSV(.datファイルなど)で保存されている書店アプリには、これに似たものを使用しました。ただし、単一文字の場合、つまり、置換文字は単一文字のみです。たとえば、「|」の場合は、二重引用符「|」で囲む必要があります。無効な変換constcharをスローしないようにするため。
#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.
これは、標準ライブラリにない唯一のメソッドではなく、低レベルであることが意図されていました。このユースケースと他の多くのユースケースは、次のような一般的なライブラリでカバーされています。
QtCoreとQStringには私の好みがあります。それは、UTF8をサポートし、使用するテンプレートが少ないため、理解できるエラーと高速なコンパイルを意味します。名前空間を不要にし、ヘッダーを簡素化する「q」プレフィックスを使用します。
Boostはしばしば恐ろしいエラーメッセージを生成し、コンパイル時間を遅くします。
POCOは妥当な妥協案のようです。