regex - 重复匹配组时,某些捕获组似乎丢失了
问题描述
尝试解析监控插件的输出时遇到了一个问题,即匹配结果出乎我的意料:
首先考虑使用 Perl 5.18.2 的调试器会话:
DB<6> x $_
0 'last=0.508798;;;0'
DB<7> x $RE
0 (?^u:^((?^u:\'[^\'=]+\'|[^\'= ]+))=((?^u:\\d+(?:\\.\\d*)?|\\.\\d+))(s|%|[KMT]?B)?(;(?^u:\\d+(?:\\.\\d*)?|\\.\\d+)?){0,4}$)
-> qr/(?^u:^((?^u:'[^'=]+'|[^'= ]+))=((?^u:\d+(?:\.\d*)?|\.\d+))(s|%|[KMT]?B)?(;(?^u:\d+(?:\.\d*)?|\.\d+)?){0,4}$)/
DB<8> @m = /$RE/
DB<9> x @m
0 'last'
1 0.508798
2 undef
3 ';0'
DB<10>
好的,正则表达式$RE
(旨在匹配“'label'=value[UOM];[warn];[crit];[min];[max]”)乍一看看起来很可怕,所以让我展示一下它的构造:
my $RE_label = qr/'[^'=]+'|[^'= ]+/;
my $RE_simple_float = qr/\d+(?:\.\d*)?|\.\d+/;
my $RE_numeric = qr/[-+]?$RE_simple_float(?:[eE][-+]?\d+)?/;
my $RE = qr/^($RE_label)=($RE_simple_float)(s|%|[KMT]?B)?(;$RE_simple_float?){0,4}$/;
相关部分(;$RE_simple_float?){0,4}$
旨在匹配 ";[warn];[crit];[min];[max]" (仍然不完美),所以对于 ";;;0" 我希望@m
以';', ';', ';0'
. 然而,除了最后一场比赛外,似乎比赛都输了。
我误解了什么,还是 Perl 错误?
解决方案
当您在捕获组之后使用{<number>}
(或+
就此*
而言)时,仅存储与捕获组匹配的最后一个值。这解释了为什么您只最终;0
而不是;;;0
在您的第四个捕获组中:(;$RE_simple_float?){0,4}
将第四个捕获组设置为它匹配的最后一个元素。
顶级修复,我建议匹配字符串的整个结尾,然后将其拆分:
my $RE = qr/...((?:;$RE_simple_float?){0,4})$/;
my @m = /$RE/;
my @end = split /;/, $m[3]; # use /(?<=;)/ to keep the semicolons
另一种解决方案是重复捕获组:替换(;$RE_simple_float?){0,4}
为
(;$RE_simple_float?)?(;$RE_simple_float?)?(;$RE_simple_float?)?(;$RE_simple_float?)?
不匹配的捕获组将设置为undef
。这种方法的问题在于它有点冗长,并且仅适用于{}
,但不适用于+
or *
。
推荐阅读
- python-3.x - Python - 在同一 Windows 命令提示符下执行顺序命令
- javascript - 组织许多六边形
- opencv - opencv-3.3.0 在 58% 处停止编译
- node.js - 使用 nodemon 和 babel Express Nodejs 应用程序崩溃而没有错误消息
- math - 负权重的加权平均计算
- android - 无法在 Firebase 中注册
- excel - “结束如果没有块如果”错误
- curl - 将 CURL 数据发送到 IBM Watson 进行识别
- mosquitto - mosquitto PSK 加密不起作用
- css - 在 Firefox 开发者工具中自动将 CSS “简写”转换为“简写”