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

问题描述 投票:3回答:4

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

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++ string algorithm
4个回答
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来查找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);
}

1
投票

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


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

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()
© www.soinside.com 2019 - 2024. All rights reserved.