3


文字列内の文字を文字列に置き換えたい。その場でできますか?新しい文字列の長さは元の文字列よりも長いため、追加のバッファーを使用してそれを行うことができますか? 例えば

void replaceChar(std::string &input, std::string replacementString, char charToReplace)
{
//some code here. No additional buffer
}

void main(){

  std::string input = "I am posting a comment on LinkedIn";
  std::string replacementString = "pppp";
  char charToReplace = 'o';
  replaceChar(input, replacementString, charToReplace);
}

戦略(アルゴリズム)だけが欲しい。C ++のように初期化された後、文字列の長さを動的に増減しない言語を念頭に置いてアルゴリズムが設計されるとよいでしょう

4

4 に答える 4

6

std::stringにはreplaceメンバーがありますが、文字列の以前の内容ではなく、数値の位置に関して機能します。そのため、通常はfind次のようにループ内のメンバーと結合する必要があります。

std::string old("o");

int pos;

while ((pos = x.find(old)) != std::string::npos)
    x.replace(pos, old.length(), "pppp");

個人的には、文字列のサイズが変更される頻度について気にすることはめったにありませんが、それが大きな懸念事項である場合は、 を使用std::countして文字列の出現回数を見つけ、old古い文字列と新しい文字列のサイズの差を掛けて、std::string::reserve()十分なスペースを確保するために使用します。ただし、これreserveは C++11 で追加されたことに注意してください。古い実装にはありません。

編集: @ipc が指摘したように、使用した文字列には問題はありませんが、置換文字列に置換される値のインスタンスが含まれている場合、これは正しく機能しません。それに対処する必要がある場合は、各検索を開始する文字列のオフセットを指定する必要があります。

int pos = 0;

while ((pos = x.find(old, pos)) != std::string::npos) {
    x.replace(pos, old.length(), rep);
    pos += rep.length();
}

forまたは、この場合はループを好むかもしれません:

    std::string old("o");
    std::string rep("pop");

for (int pos=0; 
    (pos = x.find(old, pos)) != std::string::npos; 
    pos+=rep.length())
{
    x.replace(pos, old.length(), rep);
}
于 2012-04-05T15:05:50.547 に答える
1

C++ std::string を誤解していると思います。実際には文字列の長さを動的に変更できます。内部でヒープ割り当てを行い、必要に応じてバッファを拡張します。

于 2012-04-05T14:47:32.357 に答える
1

これは、割り当てと割り当ての数を最小限に抑えるコードです。これは、同様の質問に対する次の回答に基づいています: https://stackoverflow.com/a/32322122/3903076

置換文字列の長さが 0 または 1 の場合は、個別に処理されます。それ以外の場合、文字列は成長する必要があります。

十分な容量がない場合は、とにかく外部バッファーが必要になるため、コピーと置換とスワップを行うだけです。

興味深いケースは、文字列がすでに十分な容量を持っている場合です。そのため、重要なインプレース置換を実際に行うことができます。逆のコピー置換でそれを行い、他に何も置換する必要がなくなったら停止します。

これは、関数の最後の行で確認できます。

void replaceChar(std::string& input, const std::string& replacementString, char charToReplace)
{
  if (replacementString.empty()) {
    input.erase(std::remove(input.begin(), input.end(), charToReplace), input.end());
    return;
  }
  if (replacementString.size() == 1) {
    std::replace(input.begin(), input.end(), charToReplace, replacementString.front());
    return;
  }

  const auto first_instance = std::find(input.begin(), input.end(), charToReplace);
  auto count = std::count(first_instance, input.end(), charToReplace);
  const auto extra_size = count * (replacementString.size() - 1);
  const auto new_size = input.size() + extra_size;

  if (input.capacity() < new_size) {
    std::string aux;
    aux.reserve(new_size);
    replace_with_range_copy(input.cbegin(), input.cend(), std::back_inserter(aux), charToReplace, replacementString.cbegin(), replacementString.cend());
    input.swap(aux);
    return;
  }

  input.resize(new_size);

  const auto rlast = std::make_reverse_iterator(first_instance);
  const auto rfirst = input.rbegin();
  const auto old_rfirst = rfirst + extra_size;

  replace_with_range_copy(old_rfirst, rlast, rfirst, charToReplace, replacementString.crbegin(), replacementString.crend());
}

replace_with_range_copyアルゴリズムの実装は次のとおりです。

template <typename InputIt1, typename OutputIt, typename T, typename InputIt2>
OutputIt replace_with_range_copy(InputIt1 first, InputIt1 last, OutputIt d_first, const T& old_value, InputIt2 new_first, InputIt2 new_last)
{
  InputIt1 next;
  while (true) {
    if (first == last) return d_first;
    next = std::find(first, last, old_value);
    d_first = std::copy(first, next, d_first);
    if (next == last) return d_first;
    d_first = std::copy(new_first, new_last, d_first);
    first = std::next(next);
  }
}
于 2016-02-12T19:43:17.470 に答える