这个问题可能是重复的,例如在c++中删除字符串的双引号但我看到的答案都没有解决我的问题
我有一个字符串列表,有些是双引号,有些不是,引号总是在开头和结尾
std::vector<std::string> words = boost::assign::list_of("words")( ""some"")( "of which")( ""might"")("be quoted");
我正在寻找最有效的方法来删除引号。这是我的尝试
for(std::vector<std::string>::iterator pos = words.begin(); pos != words.end(); ++pos)
{
boost::algorithm::replace_first(*pos, """, "");
boost::algorithm::replace_last(*pos, """, "");
cout << *pos << endl;
}
我还能做得更好吗?我可能有成千上万的字符串要处理。它们可能来自文件或数据库。示例中的std::vector仅用于说明目的。
如果您知道引号总是出现在第一个和最后一个位置,您可以直接
if ( s.front() == '"' ) {
s.erase( 0, 1 ); // erase the first character
s.erase( s.size() - 1 ); // erase the last character
}
复杂度在字符串的大小上仍然是线性的。不能在0(1)时间内从std::string
的开头插入或删除。如果可以用空格替换字符,那么就这样做。
检查一下可能会比较快:
for (auto i = words.begin(); i != words.end(); ++i)
if (*(i->begin()) == '"')
if (*(i->rbegin()) == '"')
*i = i->substr(1, i->length() - 2);
else
*i = i->substr(1, i->length() - 1);
else if (*(i->rbegin()) == '"')
*i = i->substr(0, i->length() - 1);
它可能不是最漂亮的东西,但它是O(n)加上一个小常数。
现代c++最有效的方法是:
if (str.size() > 1) {
if (str.front() == '"' && str.back() == '"') {
if (str.size() == 2) {
str.erase();
} else {
str.erase(str.begin());
str.erase(str.end() - 1);
}
}
}
原理:
-
erase()
函数修改字符串而不是重新分配字符串。 - 在空字符串上调用
front()
会触发未定义行为。 - 这段代码对编译器推断两个
erase
调用的意图并进一步优化代码的可能性是开放的(一起删除第一个和最后一个字符是一个标准问题)。
我是这样处理这种情况的:
- Start Simple:从最简单的方法开始,就像potatoswater的答案。
-
不要存储引号字符串:如果你可以帮助它,不要存储引号字符串。在创建
std::vector<std::string>
的地方检查并取消对字符串的引用。如果你只是收到一个std::vector<std::string>
,你不能做太多,因为删除第一个引号将需要复制字符串的其余部分。 - Profile/Benchmark:您可能会惊讶于几个100000个字符串的迭代速度有多快,而最终任何微优化都不会给您带来什么。总有一些情况下,你确实需要一点速度,但一定要了解如何实现最大的收益(分析会告诉你)。
- 最坏情况:如果你必须在取消引号时防止复制整个字符串,那么存储索引/迭代器到第一个"真实"字符。对于"短"字符串,这实际上可能会慢一些,但对于"长"字符串(即mb大小)可能会有效。你也可以创建,或者找到,一个字符串类来处理移动字符串开始而不复制,但这将是我最后的选择。