【问题标题】:How to efficiently remove double quotes from std::string if they exist如何有效地从 std::string 中删除双引号(如果存在)
【发布时间】:2011-09-11 14:34:57
【问题描述】:

这个问题有重复的风险,例如remove double quotes from a string in 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 仅用于说明目的。

【问题讨论】:

  • 听起来你最好不要在数据中首先包含引号?
  • @Tomalak 如果我们可以选择我们必须使用的数据:)
  • @Seth:有时,我们可以。有时,我们拥有数据源并试图修复错误的东西。
  • @Potatoswatter 该字符串具有可变长度。有的很短有的很长
  • @Tomalak 如果他有选择的话,我怀疑他会对自己施加奇怪的限制和要求。

标签: c++ stdstring


【解决方案1】:

如果你知道引号总是出现在第一个和最后一个位置,你可以这样做

if ( s.front() == '"' ) {
    s.erase( 0, 1 ); // erase the first character
    s.erase( s.size() - 1 ); // erase the last character
}

复杂度在字符串的大小上仍然是线性的。您不能在 O(1) 时间内从 std::string 的开头插入或删除。如果用空格替换字符是可以接受的,那么就这样做。

【讨论】:

  • 有些被引用,有些没有。
  • @Seth:这就是“如果”的作用。无论如何,我们在这里并没有真正的问题描述。字符串中的转义引号怎么样?谁知道?
  • 哎呀,我的眼睛跳过了if,以为它是迭代向量的for,抱歉。一直发生在我身上。是的,问题没有明确说明。
  • @Potatoswatter 这看起来很优雅而且目的很明确,问题是如果字符串仅在开头有引号(数据错误的情况),我可能会在末尾删除非引号
  • 我认为这个答案比 Seth 的更好,因为它更简单且分配成本更低。具体来说,Seth 总是会从 substr 调用中分配一个新字符串,而这个调用中的 s.erase(0,1) 将原地复制字符。 s.erase(s.size()-1) 会比 s.pop_back() 更具可读性,并且大约是两个分配,所以可能可以忽略不计。
【解决方案2】:

做个检查可能会很快:

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) 和一个小的常数。

【讨论】:

  • 我会等待专家参与,因为我不确定我是否理解您的代码在做什么
  • @molita 你有什么不明白的?这里是这样的话:如果第一个字符是“然后:如果最后一个字符是”,则将第一个和最后一个字符切掉,否则将第一个字符切掉。否则,如果最后一个字符是 ",则去掉最后一个字符。
  • 其实我现在想。最初我看到很多 *s 并认为你在做我不太明白的原始指针算术,但你正在取消引用迭代器,现在它是有道理的。
  • 如果你有C++11,你可以把丑陋的*(i-&gt;begin())*(i-&gt;rbegin())改成i-&gt;front()i-&gt;back()。更具可读性。
  • 如果你的字符串是一个字符长并且是",那么你就有问题了
【解决方案3】:

这就是我处理这种情况的方式:

  • 从简单开始:从最简单的方法开始,比如 Potatoswatter 的回答。
  • 不要存储带引号的字符串:如果可以,请不要存储带引号的字符串。首先在您创建std::vector&lt;std::string&gt; 的地方检查并取消引用字符串。如果您只是收到std::vector&lt;std::string&gt;,则您无能为力,因为删除第一个引号将需要复制字符串的其余部分。
  • 配置文件/基准测试:您可能会惊讶于 100000 个字符串的迭代速度有多快,而最终的微优化却很少。在某些情况下,您确实需要一点点速度,但请确保了解如何获得最大收益(分析会告诉您)。
  • 最坏情况:如果您在取消引用时绝对必须防止复制整个字符串,则将索引/迭代器存储到第一个“真实”字符。这实际上对于“短”字符串可能会更慢,但可能适用于“长”字符串(即,大小为兆字节)。您还可以创建或查找一个字符串类来处理移动字符串开头而不复制,但这是我的最后选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多