正则表达式作为标记器 - 以分隔符开头的字符串
Posted
技术标签:
【中文标题】正则表达式作为标记器 - 以分隔符开头的字符串【英文标题】:regex as tokenizer - string beginning with delimiter 【发布时间】:2012-03-21 01:05:45 【问题描述】:当子匹配的索引被指定为 -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 迭代器枚举最后一个子表达式,该子表达式包含从最后一个正则表达式匹配的结尾到被枚举的输入序列结尾的所有字符,前提是这个 不会是空子表达式。
有谁知道指定这种看似不对称的行为的原因是什么?
最后,是否有一个优雅的解决方案来完成这项工作? (这样我们根本就没有空条目)。
【问题讨论】:
我有点好奇为什么你会希望分词器丢弃分隔符——用定界符开始输入可能是你的语言错误,如果分词器把它扔掉,您无法确定您的代码应该无法解析输入。你能在你的语法水平上处理这个吗? 不,我现在并没有真正处理具体的问题,只是想知道这是否可行。 更优雅的解决方案:使用真正的分词器,例如Boost.Tokenizer。 :P 【参考方案1】:显然您的正则表达式匹配 - 分隔符之间的空字符串,一个简单(不一定是优雅的解决方案)将丢弃所有长度为零的字符串:
...
string aux = (string) *it;
if(aux.size() > 0)
cout << aux << endl;
...
【讨论】:
我会使用aux.empty()
而不是检查大小。
@JoachimPileborg 你说得对,aux.empty() 是一个更干净、更优雅的解决方案。【参考方案2】:
似乎当您将-1
作为第三个参数传递时,您实际上是在进行拆分,这是拆分的预期行为。第一个标记是第一个分隔符之前的任何内容,最后一个标记是最后一个分隔符之后的任何内容。在这种情况下,两者恰好都是空字符串,split()
的传统做法是在末尾删除任何空标记,但保留开头的那些。
只是出于好奇,你为什么不自己匹配令牌呢?如果"-+"
是分隔符的正确正则表达式,则它应该与标记匹配:
regex r("[^-+");
【讨论】:
有趣的答案。我从来没有注意到关于分裂的事实。你能指出我其他行为相同的字符串实现吗?同样,我只是想了解这种行为,如果我确实在解决问题,我会选择您的替代解决方案 =)以上是关于正则表达式作为标记器 - 以分隔符开头的字符串的主要内容,如果未能解决你的问题,请参考以下文章
1 到 150 之间的有效字符串的正则表达式,以逗号和连字符分隔
求一个匹配 以指定字符开头,指定字符结尾,中间内容任意的正则表达式