在reg exp中使用已定义的子模式时,它不会选择最佳匹配,但会在第一次匹配时停止。我忘记了一些旗帜吗?
正则表达式:(?<minutes>[0-9]|[1-5][0-9]):(?&minutes);
测试字符串:47:24;
。
表达式不匹配:
但字符串47:2;
已正确匹配:
如果我改变了或者#39;条件为[1-5][0-9]|[0-9]
,reg exp (?<minutes>[1-5][0-9]|[0-9]):(?&minutes);
效果很好。还有其他方法可以制作字符串&#39; 47:24;&#39;匹配而不反转&#39;或&#39;条件?
答案 0 :(得分:3)
模式从左到右匹配,替代品也从左到右尝试。这就是NFA正则表达式引擎的工作方式。 PCRE还有一个DFA引擎,它会尝试找到最长的匹配,但它不会暴露给PHP。
因此,如果您的模式类似a|b
且b
是a
的子集,则引擎会首先尝试a
并成功。 <{1}}部分将从不匹配。
你可以写b
,但这似乎是多余的。
只需使用\b(?:[1-5][0-9]|[0-9])\b
(如stribizhev建议的那样)一直使用它。 \b[1-5]?[0-9]\b
是一个单词边界,它会确保您匹配整数,而不是jsut更大数字的几个数字。
答案 1 :(得分:2)
使用PCRE,递归组是原子的(请参阅此article)。这就是正则表达式引擎无法在(?&minutes)
中回溯的原因。
在42:24;
中,2
的{{1}}与第一个分支24
匹配(自第一次获胜以来),但是当模式失败时,因为有{ {1}}在字符串中而不是[0-9]
,正则表达式引擎无法在4
子模式内回溯以测试第二个分支;
。 (您可以查看debugger)
解决方案:不要对如此小的子模式使用递归,它没用,也毫无意义(特别是如果你使用捕获组的名称)。写点如下:
(?&minutes)
或为什么不:
[1-5][0-9]
似乎是多余的,但是如果你想提取分钟和秒钟(或者根本不使用组),它是有意义的并且很有用。毕竟,如果你使用命名捕获,你的目标不是写出世界上最短的模式。
如果你无法避免改变:
(?<minutes>[1-5]?[0-9]):(?<seconds>[1-5]?[0-9]);
。(?(DEFINE)(?<sex>[1-5]?[0-9]) for "sexagesimal", not for what you think)
(?<minutes>(?&sex)):(?<seconds>(?&sex));
,[1-5][0-9]|[0-9]
(在这种情况下订单无关紧要) 请注意,递归组的这种行为特别适用于PCRE,它与Perl或Ruby不同。