"contains 10-14 digits" 的正则表达式正前瞻无法正常工作

Regex positive lookahead for "contains 10-14 digits" not working right

我有一个正则表达式,用于验证 phone 数字字符串是空的,还是包含任何格式的 10-14 位数字。它适用于至少需要 10 个数字但继续匹配超过 14 个数字。我以前很少使用前瞻,也没有看到问题。这是评论中的预期解释:

///  ^                      - Beginning of string
/// (?=                     - Look ahead from current position
///      (?:\D*\d){10,14}       - Match 0 or more non-digits followed by a digit, 10-14 times
///      \D*$                   - Ending with 0 or more non-digits
/// .*                      - Allow any string
/// $                       - End of string
^(?=(?:\D*\d){10,14}\D*|\s*$).*$

这在 asp.net MVC 5 站点中使用 System.ComponentModel.DataAnnotations.RegularExpressionAttribute,因此它在服务器端使用 .NET 正则表达式,在 javascript 客户端使用 jquery 验证。如果字符串包含超过 14 位数字,如何让它停止匹配?

正则表达式的问题

^(?=(?:\D*\d){10,14}\D*|\s*$).*$

\D|之间没有行尾锚点。例如,考虑字符串

12345678901234567890

其中包含 20 位数字。前瞻将得到满足,因为 (?:\D*\d){10,14} 将匹配

12345678901234

然后 \D* 将匹配零个非数字。相比之下,正则表达式

^(?=(?:\D*\d){10,14}\D*$|\s*$).*$

会失败(因为它应该)。

但是,不需要向前看。可以将前面的表达式简化为

^(?:(?:\D*\d){10,14}\D*)?$

Demo

将外部非捕获组设为可选允许正则表达式根据需要匹配空字符串。

最后一个正则表达式可能有问题,如 link 所示。考虑字符串

\nabc12\nab12c3456d789efg

(?:\D*\d) 的第一个匹配项是 \nabc1(因为 \D 匹配换行符),第二个匹配项是 2,第三个匹配项是 \nab1,以此类推,共匹配11个,满足10-14个数字的要求。这无疑不是故意的。解决方案是将正则表达式更改为

^(?:(?:[^\d\n]*\d){10,14}[^\d\n]*)?$

[^\d\n] 匹配数字和换行符以外的任何字符。

Demo