c++ 将字符串中的字符替换为某个字符串中的字符

t5fffqht  于 2023-04-01  发布在  其他
关注(0)|答案(4)|浏览(150)

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

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++初始化

lbsnaicq

lbsnaicq1#

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中添加的-旧的实现不会有它。
虽然这与你使用的字符串无关,但如果替换字符串包含被替换值的示例,这将无法正常工作。如果你需要处理这个问题,你需要在字符串中提供每次搜索开始的偏移量:

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 (std::size_t pos=0; 
    (pos = x.find(old, pos)) != std::string::npos; 
    pos+=rep.length())
{
    x.replace(pos, old.length(), rep);
}
j9per5c4

j9per5c42#

我想你误解了C++ std::string。它实际上可以动态地改变字符串的长度。在内部进行堆分配,如果需要的话会增加缓冲区。

ippsafx7

ippsafx73#

下面是一个最小化赋值和分配数量的代码。它基于以下类似问题的答案: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);
  }
}
ilmyapht

ilmyapht4#

我尝试了这个老式的东西,我认为它的工作。在这里它是。我不知道这将工作的编码以外的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()

相关问题