正则表达式错误的思维过程

时间:2015-12-22 13:39:11

标签: regex

我想了解正则表达式。我一点一点地理解它,但我完全不理解这一点。它基本上是完全合格域名的正则表达式,但要求是结尾不能是.arpa。

(?=^.{4,253}$)(^([a-zA-Z0-9]{1,63}\.)+[a-zA-Z]{2,63}[^.arpa]$)

https://regex101.com/r/hU6tP0/3

这与google.uk不匹配。 如果我把它改为

(?=^.{4,253}$)(^([a-zA-Z0-9]{1,63}\.)+[a-zA-Z]{1,63}[^.arpa]$)

再次有效。

但这也适用

    (?=^.{4,253}$)(^([a-zA-Z0-9]{1,63}\.)+[a-zA-Z]{2,63}$)

我想知道为什么:

这是

的思考过程
?=^.{4,253}$)(^([a-zA-Z0-9]{1,63}\.)+[a-zA-Z]{2,63}[^.arpa]$)

我认为这是

(?=

是一个积极向前看(有人可以向我解释这实际意味着什么)正如我现在所理解的那样它只是意味着字符串需要匹配正则表达式

^.{4,253}$)

匹配所有字符,但长度必须介于4到253个字符之间。

(^([a-zA-Z0-9]{1,63}\.)

启动捕获组并在其中创建另一个捕获组。这个捕获组说每个非特殊字符可写1到63次或直到。是写的。

+

以前的捕获组可以无限期重复。但它应该总是以一个结束。这样就可以启动下一个捕获组。

[a-zA-Z]{2,63}

然后根据需要多次编写带上部的z,但需要介于2到63之间

[^.arpa]$)

最后一个字符不能是.arpa

有人能告诉我哪里出错了。

编辑:这两个答案都值得一试。

2 个答案:

答案 0 :(得分:3)

这不符合你的想法:

[^.arpa]

所有这一切都是'结尾的东西不是字母apr.' - 它是一个否定的字符类。

您可能会想到negative lookahead assertion

(?!\.arpa)$

但如果你试图在正则表达式中复合多个标准,我建议你可能正在使用错误的工具来完成工作。由于贪婪/非贪婪的匹配等,它最终变得复杂且难以调试。

你的'正面/负面'前瞻是为了匹配一块未被其他图案包围的图案。但是如果你匹配变量宽度,那可能会有一些意想不到的结果,因为正则表达式引擎会回溯,直到找到匹配的某事

一个更简单的例子:

([\瓦特] +)(?ARPA)$

适用于:

www.test.arpa

会匹配吗?小组里有什么?

...它会匹配,因为[\w\.]+将消耗所有这些,然后前瞻不会“看到”任何东西。

如果您使用:

([\w]+)\.(?!arpa)

相反,你会捕捉...... www,但你不会匹配test(例如g标志,因为{{1} }之后没有www,但.arpa没有。{/ p>

test

因此,在模式中使用否定断言确实变得复杂。我建议不要这样做,并应用两个单独的测试。你很难弄明白,对未来的维护程序员来说也很难!

答案 1 :(得分:2)

这是对你的正则表达式的分析:

(?=^.{4,253}$)              # force min length: 4 chars, max length: 253 chars
(                           # Capturing Group 1 (CG1) - not needed
    ^                       # Match start of the string
    (                       # CG2 (can be a non capturing group '(?:...)')
      [a-zA-Z0-9]{1,63}     # any sequence of letters and numbers with length between 1 and 63
      \.                    # a literal dot
    )+                      # CLOSE CG2
    [a-zA-Z]{1,63}          # any letter sequence with length between 1 to 63 
    [^.arpa]                # a negated char class: any char that is not a "literal" '.','a','r','p' (last 'a' is redundant)
  $                         # end of the string
)                           # CLOSE CG1

要避免字符串的尾部为.arpa,您需要使用否定前瞻(?!...),因此请按以下方式进行修改:

(?=^.{4,253}$)(?!.*\.arpa$)(^([a-zA-Z0-9]{1,63}\.)+[a-zA-Z]{2,63}$)

An online demo

更新

我升级了正则表达式以使其合理化(我已经将Sobrique建议添加到了一个重要的细节中):

 /^(?=.{4,253}$)([a-z0-9]{1,63}[.])+(?!arpa$)[a-z]{2,63}$/i

Compact version online demo

<强>勒亘

/                     # js regex delimiter
 ^                    # start of the string
   (?=.{4,253}$)      # force min length: 4 chars, max length: 253 chars
   (?:                # Non capturing group 1 (NCG1)
     [a-z0-9]{1,63}   # any letter or digit in a sequence with length from 1 to 63 chars
     [.]              # a literal dot '.' (more readable than \.)
   )+                 # CLOSE NCG1 - repeat its content one or more time
   (?!arpa$)          # force that after the last literal dot '.' the string does not end with 'arpa' (i've added '$' to Sobrique suggestion instead it prevents also '.arpanet' too)
   [a-z]{2,63}        # a sequence of letters with length from 2 to 63
 $                    # end of the string
/i                    # Close the regex delimiter and add case insensitive flag [a-z] match also [A-Z] and viceversa

var re = /^(?=.{4,253}$)([a-z0-9]{1,63}[.])+(?!arpa$)[a-z]{2,63}$/i;

var tests = ['google.uk','domain.arpa','domain.arpa2','another.domain.arpa.net','domain.arpanet'];
var m;

while(t = tests.pop()) {
    document.getElementById("r").innerHTML += '"' + t + '"<br/>';
    document.getElementById("r").innerHTML += 'Valid domain? ' + ( (t.match(re)) ? '<font color="green">YES</font>' : '<font color="red">NO</font>') + '<br/><br/>';
}
    
<div id="r"/>