Replace char in string with some string inplace

前端 未结 4 1604
刺人心
刺人心 2021-01-14 16:16


i want to replace a character in the string with a string. can i do it in-place? As the new string has length greater than original string.Question is that can i do with

4条回答
  •  孤街浪徒
    2021-01-14 16:36

    Here is a code that minimises the number of assignments and allocations. It is based on the following answer to a similar question: https://stackoverflow.com/a/32322122/3903076

    The cases where the replacement string has length 0 or 1 are handled separately. Else, the string has to grow.

    If there is not enough capacity, then an external buffer will be necessary anyway, so we just do copy-replace and swap.

    The interesting case is when the string already has enough capacity, so we can actually do a non-trivial in-place replacement. We do that with a reverse copy-replace, stopping when we do not need to replace anything else.

    This can be seen in the last line of the function.

    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());
    }
    

    Here is an implementation of the replace_with_range_copy algorithm:

    template 
    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);
      }
    }
    

提交回复
热议问题