理解正则表达式中的负向前瞻

Yar*_*rin 4 ruby regex

我想使用Ruby regex匹配不包含字符串'localhost'的URL

根据这里的答案和评论,我将两个解决方案放在一起,这两个解决方案似乎都有效:

解决方案A:

(?!.*localhost)^.*$ 
Run Code Online (Sandbox Code Playgroud)

示例:http://rubular.com/r/tQtbWacl3g

解决方案B:

^((?!localhost).)*$ 
Run Code Online (Sandbox Code Playgroud)

示例:http://rubular.com/r/2KKnQZUMwf

问题是我不明白他们在做什么.例如,根据文档,^可以以各种方式使用:

[^abc]  Any single character except: a, b, or c  
^ Start of line  
Run Code Online (Sandbox Code Playgroud)

但我不知道它是如何在这里应用的.

有人可以为我分解这些表达方式,以及它们之间的区别吗?

Mar*_*der 5

在这两种情况下,^只是行的开头(因为它没有在字符类中使用).由于两者^和前瞻都是零宽度断言,我们可以在第一种情况下切换它们 - 我认为这使得它更容易解释:

^(?!.*localhost).*$ 
Run Code Online (Sandbox Code Playgroud)

^表达式锚定到字符串的开头.然后前瞻从那个位置开始,并试图找到localhost字符串的任何地方("任何地方"由.*前面的处理localhost).如果localhost可以找到,则前瞻的子表达式匹配,因此前瞻导致模式失败.由于前瞻必然是通过相邻的^这个方式从字符串的开头开始,所以整个模式不能匹配.但是,.*localhost如果不匹配(因此localhost不会出现在字符串中),则前瞻成功,并且.*$只需处理匹配字符串的其余部分.

现在是另一个

^((?!localhost).)*$
Run Code Online (Sandbox Code Playgroud)

这一次,前瞻只检查当前位置(里面没有.*).但是每个角色都会重复前瞻.这样它可以再次检查每个位置.这大致是发生了什么:^确保我们再次从字符串的开头开始.前瞻检查是否localhost在该位置找到了该单词.如果没有,一切都很好,.消耗一个字符.在*随后重复两者的那些步骤.我们现在是字符串中的一个字符,并且前瞻检查第二个字符是否开始单词localhost- 如果没有,则一切都很好,并.消耗另一个字符.这是为字符串中的每个字符完成的,直到我们到达结尾.

在这种特殊情况下,两种方法都是等效的,您可以根据性能(如果重要)或可读性(如果不是;可能是第一种)选择一种方法.但是,在其他情况下,第二个变体是首选,因为它允许您对字符串的固定部分执行此重复,而第一个变体将始终检查整个字符串.