正则表达式作为标记化器 - 以分隔符开头的字符串

时间:2012-03-21 01:05:45

标签: c++ regex string c++11 tokenize

当子匹配的索引指定为-1时,

sregex_token_iterator几乎完美地用作标记器。但不幸的是,对于以分隔符开头的字符串,它不能很好地工作,例如:

#include <string>
#include <regex>
#include <iostream>
using namespace std;

int main()
{
    string s("--aa---b-c--d--");
    regex r("-+");

    for (sregex_token_iterator it = sregex_token_iterator(s.begin(), s.end(), r, -1); it != sregex_token_iterator(); ++it)
    {
        cout << (string) *it << endl;
    }

    return 0;
}

打印出来:

  


  aa
  b
  c
  d

(注意前面的空行)。

请注意,它实际上很好地处理尾随的分隔符(因为它不会打印额外的空行)。

阅读标准似乎有一个专门处理尾随分隔符的条款,即:

[re.tokiter] no 4.

  

如果到达序列的末尾(位置等于序列迭代器的结尾),则迭代器变得等于序列结束迭代器值,除非枚举的子表达式具有索引-1,其中case迭代器枚举最后一个子表达式,该子表达式包含从最后一个正则表达式匹配结束到枚举输入序列结尾的所有字符,前提是这个   不会是一个空的子表达式。

有谁知道这个看似不对称行为被指定的原因是什么?

最后,是否有一个优雅的解决方案使这项工作? (这样我们根本就没有空条目。)

2 个答案:

答案 0 :(得分:1)

显然你的正则表达式匹配 - 分隔符之间的空字符串,一个简单的(不一定是优雅的解决方案)将丢弃长度为零的所有字符串:

...  
string aux = (string) *it;  
if(aux.size() > 0){  
    cout << aux << endl;  
}
...  

答案 1 :(得分:1)

当您传递-1作为第三个参数时,您实际上正在进行拆分,这就是拆分的预期行为。第一个标记是第一个分隔符之前的标记,最后一个标记是最后一个分隔符之后的标记。在这种情况下,两者都恰好是空字符串,而传统的split()最终会丢弃任何空标记,但要将它们保留在开头。

出于好奇,你为什么不匹配令牌呢?如果"-+"是分隔符的正确正则表达式,则应该与标记匹配:

regex r("[^-}+");