18

次の文字列を考えると、"Hi ~+ and ^*. Is ^* still flying around ~+?"

"~+"and"^*"をすべて "Bobby" と "Danny"に置き換えたいので、文字列は次のようになります。

"Hi Bobby and Danny. Is Danny still flying around Bobby?"

2 つの異なる値の出現を置き換えるために、Boost replace 関数を 2 回呼び出す必要はありません。

4

5 に答える 5

7

Boost.Iostreams を使用して、必要な置換機能を実装することができました。具体的には、私が使用した方法は、正規表現を使用して何を置き換えるかを一致させるフィルタリング ストリームでした。ギガバイトサイズのファイルでのパフォーマンスについてはわかりません。もちろん、テストする必要があります。とにかく、ここにコードがあります:

#include <boost/regex.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <iostream>

int main()
{
   using namespace boost::iostreams;

   regex_filter filter1(boost::regex("~\\+"), "Bobby");
   regex_filter filter2(boost::regex("\\^\\*"), "Danny");

   filtering_ostream out;
   out.push(filter1);
   out.push(filter2);
   out.push(std::cout);

   out << "Hi ~+ and ^*. Is ^* still flying around ~+?" << std::endl;

   // for file conversion, use this line instead:
   //out << std::cin.rdbuf();
}

期待どおり、実行時に上記の出力が表示"Hi Bobby and Danny. Is Danny still flying around Bobby?"されます。

測定することにした場合は、パフォーマンスの結果を確認するのは興味深いことです。

ダニエル

regex_filter編集:文字シーケンス全体をメモリに読み込む必要があるため、ギガバイトサイズの入力にはほとんど役に立たないことに気付きました。しかたがない...

于 2010-10-09T18:01:18.213 に答える
3

これがアクティブになってから1年が経ちましたが、それだけの価値があることに気付きました. 今日、この問題を解決すると主張するCodeProject の記事に出くわしました。そこからのアイデアを使用できるかもしれません。

その正しさを保証することはできませんが、一見の価値があるかもしれません。:)

実装では、文字列全体をメモリに保持する必要がありますが、入力をブロックに分割し、その位置で決して分割しないことを保証できる限り、(置換を実行する他の実装と同様に) 簡単に回避できます。置換するシンボル内。(あなたのケースでそれを行う簡単な方法の 1 つは、次の文字がシンボルで使用される文字のいずれでもない位置で分割することです。)

--

「ReplaceMultiple」メソッドを文字列ライブラリに追加するには、パフォーマンスを超えた理由があります (私の本では十分な理由ですが)。単純に置換操作を N 回実行することは、一般的に正しくありません。

シンボルに代入される値が制約されていない場合、その後の置換操作で値がシンボルとして扱われる可能性があります。(実際にこれが必要な状況もあるかもしれませんが、そうでない場合もあります。奇妙に見える記号を使用すると、問題の深刻度は軽減されますが、解決にはなりません。フォーマットされる文字列はユーザ​​ーが定義できる場合があるため、エキゾチックな文字は必要ありません。)

ただし、一般的な複数置換の実装を簡単に見つけることができないのには十分な理由があると思います。「ReplaceMultiple」操作は、(明らかに) 一般的に明確に定義されていません。

これを確認するには、「'aa' を '!' に置き換える」とはどういう意味かを考えてみてください。および「baa」と「?」文字列 'abaa' で"? 結果は「ab!」または「?」- または、そのような交換は違法ですか?

シンボルに「プレフィックスなし」を要求することもできますが、多くの場合、それは受け入れられません。これを使用して、テンプレート テキストの書式を設定したいとします。そして、私のテンプレートがコード用であるとしましょう。「§table」を、実行時にのみ認識されるデータベース テーブル名に置き換えたいと考えています。同じテンプレートで「§t」が使えなくなったら困ります。テンプレート化されたスクリプトは、完全に一般的なものである可能性があり、驚くべきことに、ある日、テーブル名に実際に「§」を使用しているクライアントに遭遇しました...潜在的に私のテンプレートライブラリの有用性を低下させます。

おそらくより良い解決策は、単にリテラルを置き換えるのではなく、再帰降下パーサーを使用することです。:)

于 2012-01-13T11:58:13.763 に答える
0

BoostFormatライブラリを使用することをお勧めします。の代わりに、~+and^*を使用%1%%2%、以下同様に、もう少し体系的に使用します。

ドキュメントからの例:

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
     // prints "writing toto,  x=40.230 : 50-th try"

乾杯&hth。、

–アルフ

于 2010-10-09T00:23:45.617 に答える
0

Boost string_algo には replace_all 関数があります。あなたはそれを使うことができます。

于 2010-10-09T00:12:44.500 に答える
0

std::map を使用することをお勧めします。したがって、一連の置換があるので、次のようにします。

std::map<std::string,std::string> replace;
replace["~+"]=Bobby;
replace["^*"]=Danny;

次に、文字列を文字列のベクトルに入れ、各文字列がマップ内にあるかどうかを確認し、置換する場合は、最後から句読点を取り除く必要もあります。または、それらを置換に追加します。その後、1 つのループで実行できます。ただし、これが実際にブーストよりも効率的または有用かどうかはわかりません。

于 2010-10-09T19:57:03.080 に答える