【发布时间】:2013-12-18 01:07:03
【问题描述】:
我正在使用以下内容:
replace (str1.begin(), str1.end(), 'a' , '')
但这会导致编译错误。
【问题讨论】:
-
''确实不是字符。 -
嗯,知道你遇到的错误肯定会有所帮助。
-
很好,在很多情况下替换是一个合适的想法,而不是这个。
我正在使用以下内容:
replace (str1.begin(), str1.end(), 'a' , '')
但这会导致编译错误。
【问题讨论】:
'' 确实不是字符。
使用copy_if:
#include <string>
#include <iostream>
#include <algorithm>
int main() {
std::string s1 = "a1a2b3c4a5";
std::string s2;
std::copy_if(s1.begin(), s1.end(), std::back_inserter(s2),
[](char c){
std::string exclude = "a";
return exclude.find(c) == std::string::npos;}
);
std::cout << s2 << '\n';
return 0;
}
【讨论】:
s1 比固定大小的字符串s2 长,此代码会导致缓冲区溢出。此外,s2 没有正确终止,因为s1 末尾的 NUL 字节没有被复制。最后,发帖者要求就地解决方案,而不是生成新字符串。
算法std::replace 在给定序列上按元素 工作(因此它用不同的元素替换元素,并且不能用nothing 替换它)。但是没有 empty 字符。如果你想从一个序列中移除元素,下面的元素必须被移动,而std::replace不是这样工作的。
您可以尝试将std::remove() 与str.erase()1 一起使用来实现此目的。
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
【讨论】:
从 C++20 开始,std::erase() 已添加到标准库中,它将对 str.erase() 和 std::remove() 的调用合并为一个函数:
std::erase(str, 'a');
作用于字符串的std::erase() 函数重载直接在<string> 头文件中定义,因此不需要单独的包含。为所有其他容器定义了类似的重载。
【讨论】:
我正在读取一个字符串:
"\"internet\""
我想删除引号。我使用了上面建议的std::erase 解决方案:
str.erase(std::remove(str.begin(), str.end(), '\"'), str.end());
但是当我对结果进行比较时它失败了:
if (str == "internet") {}
我实际上得到的是:
"internet "
std::erase / std::remove 解决方案在删除结尾时不会缩短字符串。我添加了这个(来自https://stackoverflow.com/a/21815483/264822):
str.erase(std::find_if(str.rbegin(), str.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), str.end());
删除尾随空格。
【讨论】:
"\"internet\"" 而不是"\"internet\" "?
比最佳答案快 70% 的解决方案
void removeCharsFromString(std::string& str, const char* charsToRemove)
{
size_t charsToRemoveLen = strlen(charsToRemove);
std::remove_if(str.begin(), str.end(), [charsToRemove, charsToRemoveLen](char ch) -> bool
{
for (int i = 0; i < charsToRemoveLen; ++i) {
if (ch == charsToRemove[i])
return true;
}
return false;
});
}
【讨论】:
此代码删除重复字符,即,如果输入是 aaabbcc,则输出将为 abc。 (此代码必须对数组进行排序才能正常工作)
cin >> s;
ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i)
if(s[i] != s[i-1])
ans += s[i];
cout << ans << endl;
【讨论】:
根据其他答案,这里还有一个示例,我删除了给定字符串中的所有特殊字符:
#include <iostream>
#include <string>
#include <algorithm>
std::string chars(".,?!.:;_,!'\"-");
int main(int argc, char const *argv){
std::string input("oi?");
std::string output = eraseSpecialChars(input);
return 0;
}
std::string eraseSpecialChars(std::string str){
std::string newStr;
newStr.assign(str);
for(int i = 0; i < str.length(); i++){
for(int j = 0; j < chars.length(); j++ ){
if(str.at(i) == chars.at(j)){
char c = str.at(i);
newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
}
}
}
return newStr;
}
输入与输出:
Input:ra,..pha
Output:rapha
Input:ovo,
Output:ovo
Input:a.vo
Output:avo
Input:oi?
Output:oi
【讨论】:
如果您有 predicate 和/或非空 output 来填充过滤后的字符串,我会考虑:
output.reserve(str.size() + output.size());
std::copy_if(str.cbegin(),
str.cend(),
std::back_inserter(output),
predicate});
在原始问题中,谓词是[](char c){return c != 'a';}
【讨论】:
string RemoveChar(string str, char c)
{
string result;
for (size_t i = 0; i < str.size(); i++)
{
char currentChar = str[i];
if (currentChar != c)
result += currentChar;
}
return result;
}
我就是这样做的。
或者你可以像安托万所说的那样做:
见this question 这回答了同样的问题。在你的情况下:
#include <algorithm> str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
【讨论】:
基本上,replace 将一个字符替换为另一个字符,'' 不是一个字符。你要找的是erase。
参见this question,它回答了同样的问题。在你的情况下:
#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
如果您愿意,也可以使用boost,例如:
#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");
所有这些都在referencewebsites 上有详细记录。但是如果你不知道这些功能,你可以很容易地用手做这种事情:
std::string output;
output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
for(size_t i = 0; i < str.size(); ++i)
if(str[i] != 'a') output += str[i];
【讨论】:
O(n^2)吗?
n 是原始字符串长度。对于每个输入字符,我进行 1 个字符测试 O(1),并附加 0 或 1 个字符。字符追加为O(1) 是否保留了足够的内存,或者O(current_length) 如果分配了新缓冲区。如果你在循环之前执行output.reserve(str.size()),这永远不会发生,并且你有一个全局O(n) 成本。否则渐近,我猜成本是O(n . log(n) ),因为 STL 容器重新分配策略。
remove 不能改变字符串的长度,所以它只是随机播放字符。然后你必须调用earse 来基本上改变字符串的长度。 See wiki
这就是我的做法:
std::string removeAll(std::string str, char c) {
size_t offset = 0;
size_t size = str.size();
size_t i = 0;
while (i < size - offset) {
if (str[i + offset] == c) {
offset++;
}
if (offset != 0) {
str[i] = str[i + offset];
}
i++;
}
str.resize(size - offset);
return str;
}
基本上每当我找到给定的字符时,我都会提前偏移并将字符重新定位到正确的索引。我不知道这是否正确或有效,我正在(再次)开始使用 C++,我将不胜感激。
【讨论】:
我猜 std:remove 方法有效,但它给包含的一些兼容性问题,所以我最终写了这个小函数:
string removeCharsFromString(const string str, char* charsToRemove )
{
char c[str.length()+1]; // + terminating char
const char *p = str.c_str();
unsigned int z=0, size = str.length();
unsigned int x;
bool rem=false;
for(x=0; x<size; x++)
{
rem = false;
for (unsigned int i = 0; charsToRemove[i] != 0; i++)
{
if (charsToRemove[i] == p[x])
{
rem = true;
break;
}
}
if (rem == false) c[z++] = p[x];
}
c[z] = '\0';
return string(c);
}
只要用作
myString = removeCharsFromString(myString, "abc\r");
它会删除所有出现的给定字符列表。
这也可能更高效一些,因为循环在第一次匹配后返回,所以我们实际上做的比较少。
【讨论】:
#include <string>
#include <algorithm>
std::string str = "YourString";
char chars[] = {'Y', 'S'};
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
将从 str 中删除大写的 Y 和 S,留下“ourtring”。
请注意,remove 是一种算法,需要包含标头 <algorithm>。
【讨论】: