Вот код, который минимизирует количество назначений и распределений. Он основан на следующем ответе на аналогичный вопрос: 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);
}
}
Где вы ожидаете лишние символы будут идти? – AShelly
Я так понимаю, что я прошу об этом, потому что я видел реализацию кода в java, которая вычисляла новую длину строки и начинала размещать символы от конца до начала. Вот почему я задаюсь вопросом, позволяет ли java этот тип изменения длины строки во время выполнения ... – Madu
Существует способ вставить строку, начинающуюся с определенной позиции, удаляя символ только в этой позиции, но это увеличит размер внутреннего буфера. – hmjd