用一些字符串替换字符串中的char

时间:2012-04-05 14:34:34

标签: c++ string algorithm

我想用字符串替换字符串中的字符。我可以就地做吗?由于新字符串的长度大于原始字符串。问题是我可以使用额外的缓冲区吗? 例如

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 个答案:

答案 0 :(得分:5)

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来查找{{1}的出现次数字符串,乘以旧字符串和新字符串之间的大小差异,并使用old保留足够的空间。但请注意,在{+ C ++ 11>中添加了std::string::reserve() - 较旧的实现无法获得它。

编辑:虽然它并不关心你使用的字符串,正如@ipc指出的那样,如果替换字符串包含要替换的值的实例,则这不能正常工作。如果您需要处理这个问题,您需要在字符串中提供开始每次搜索的偏移量:

reserve

或者,在这种情况下,您可能更喜欢int pos = 0; while ((pos = x.find(old, pos)) != std::string::npos) { x.replace(pos, old.length(), rep); pos += rep.length(); } 循环:

for

答案 1 :(得分:1)

我认为你误解了C ++ std :: string。它实际上可以动态地改变字符串长度。在内部进行堆分配,并在必要时增加缓冲区。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

我尝试了这种老式的东西,我认为它可行。这里是。 我不确定这是否适用于ascii以外的其他编码。

#include <string>
#include <cstring>

std::string
replace_char_with_string
    (const char *in_p,
     char  from_ch,
     const char *to_p)
{
    char output_c_str[strlen(in_p)*2+1], *out_p = output_c_str;
    int  to_len = strlen(to_p);

    while (*in_p)
    {
        if (*in_p == from_ch)
        {
            strcpy(out_p, to_p);
            out_p += to_len;
        }
        else
        {
            *out_p++ = *in_p;
        }

        ++in_p;
    }
    *out_p = '\0';

    std::string output(output_c_str);
    return output;
}

// example usage
std::string java_namespace_name = "com.foo.boo";
std::string cpp_namespace_name = replace_char_with_string(java_namespace_name.c_str()