これは、割り当てと割り当ての数を最小限に抑えるコードです。これは、同様の質問に対する次の回答に基づいています:
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);
}
}