99至9999999正则表达式之间的数字

时间:2019-01-09 23:37:35

标签: regex pcre regular-language

我试图生成一个正则表达式,以匹配99到9999999范围内的任何数字。我在理解生成数字范围通常如何工作方面遇到了麻烦。我设法在网上找到一个能为我完成工作的范围生成器,但我想了解它的实际工作原理。

我尝试达到此范围如下:

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

这应该匹配99,任意3位数字或任意4位数字,但是它不能按预期方式工作。经测试,它仅匹配数字99和3位数字。四位数完全不匹配。如果我只用

自己写一个4位数字的部分
[1-9][0-9][0-9][0-9]

它匹配4位数字,但是当我像第一个示例中那样构造它时,它不起作用。有人可以给我澄清一下它是如何工作的以及如何成功生成范围为99到9999999的正则表达式。

链接至演示-Here

2 个答案:

答案 0 :(得分:3)

所以您想知道它是如何工作的...

正则表达式对字符串中的数字值没有真正的了解,它只关心数字的表示方式,这就是为什么在某个范围内查找数字看起来比应该的要难。您的正则表达式引擎完全可以理解character class之类的a list中范围的唯一原因是因为字符在demo中的位置([0-9]之类的字符范围只是有效,并且同样可以理解。)

因此,要匹配99-9999999之类的范围,您必须拼写出如下内容:文字“ 99”,或者三位数不带前导零,或者四位数不带前导零,依此类推。

但这就是您的grouping所做的,对吧?而且它没有用。在测试字符串“ 9293”中,您的正则表达式仅匹配“ 929”。这里发生的是正则表达式引擎渴望返回一个完全匹配的内容-一旦找到一个匹配项,它就会返回完整匹配,即使以后可能会发生更好/更长的匹配。


这是比赛的发生方式。 (我将跳过诸如alternation via |之类的一些详细信息,因为它们在这里并不十分相关。)

第1步。

引擎将正则表达式中的第一个标记与字符串中的第一个字符进行比较

[&-~]

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

成功,他们匹配。

第2步。

然后,引擎将前进到正则表达式中的下一个标记和字符串中的下一个字符,并将它们进行比较。

9293

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

失败,没有匹配项。引擎将停止并在此处返回故障,但是您使用的是stopped and returned "99",因此它知道可以尝试使用其他表达式。

步骤3。

引擎前进到正则表达式中下一个备用表达式的第一个标记,然后倒退字符串中的位置。

9293

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

成功,他们匹配。

第4步。

继续。

9293

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

匹配。

第5步。

再来一次。

9293

(99|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9])

成功。完整的表达式匹配。无需尝试其余的替代方法。返回的匹配项是:

9293

您可能已经发现,如果输入的字符串不是“ 9923”,则步骤2将匹配,并且引擎会match and return your expected "9293"

您可能还想过,如果将备用表达式从最长到最短重新排列

929

最长的尝试将首先尝试,即shorthand character class


简化

尽管如此,它还是很罗word的,尤其是当您增加范围内的数字时。您可以做几件事来简化它。

字符类([1-9][0-9][0-9][0-9]|[1-9][0-9][0-9]|99) 可以由quantifier [0-9]表示。

\d

而不是重复它们,而是在大括号中使用greedy,如下所示:

([1-9]\d\d\d|[1-9]\d\d|99)

碰巧,量词也可以采用([1-9]\d{3}|[1-9]\d{2}|99) 的形式,因此您可以将两个相似的替代词组合在一起:

{min, max}

您可能希望它使您再次返回“ 929”,引擎非常渴望,但是默认情况下,量词为capturing group,因此它们将尽可能地尝试。这很适合您更大的期望范围:

([1-9]\d{2,3}|99)

完成

从这里开始使用它取决于所需要的正则表达式。就目前而言,括号是多余的,创建整个正则表达式本身的return 1000毫无意义。但是,当您输入如下字符串时,就会做出决定:

  

您很可能被1000格里克吃掉。

如果您想找出要吃掉多少酥油,可以使用

([1-9]\d{2,6}|99)

negative lookarounds

但是,这种排序又回到了演示的原始问题。如果它是“ 12345678 grue”(超出范围),则将匹配“ 1234567”,这可能不是您想要的。您可以使用anchors确保匹配的数字不会立即跟在(或后面)另一个数字。

[1-9]\d{2,6}|99

(?<!\d)([1-9]\d{2,6}|99)(?!\d) 的意思是“从这个位置开始,前一个字符不是数字”,而(?<!\d)意思是“从这个位置开始,下一个字符不是数字”。

因为在此处进行分组所必需,备用项周围的括号又返回了,否则,后向查找将仅是第一个备用表达式的一部分并适用于第一个备用表达式,而超前行将仅是第二个备用表达式的一部分并适用于第二个备用表达式。 / p>

另一方面,如果您要确保整个字符串由您范围内的数字组成,则您应该改用non-capturing group (?:...) {{1} }和(?!\d)(分别是字符串的开头和字符串的结尾):

^

最后,您可以将捕获组换成{{3}},所以:

$

^([1-9]\d{2,6}|99)$

您仍将获取数字作为匹配项,只是不会在组捕获中重复该数字。 (环顾四周已经无法捕捉到了,无需担心。)

答案 1 :(得分:1)

首先,您需要为正则表达式设置一些字符串边界(数字以外的任何字符,在我的示例中,我使用Model OptionsMySQL-乞求行和字符串或字符串的结尾)

尝试这个:

^