我想用字符串替换字符串中的字符。我可以就地做吗?由于新字符串的长度大于原始字符串。问题是我可以使用额外的缓冲区吗? 例如
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 ++一样被启动,就不会动态地增加或减少字符串长度,这将是一件好事
答案 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()