在Ruby的正则表达式中,向前看和向后看概念是如何支持这种零宽度断言概念的?
我刚刚浏览了文档中的概念在Ruby的正则表达式中,向前看和向后看概念是如何支持这种零宽度断言概念的?,ruby,regex,ruby-1.9.3,Ruby,Regex,Ruby 1.9.3,我刚刚浏览了文档中的概念零宽度断言。我突然想到一些问题- 为什么这样的名称零宽度断言? 向前看和向后看概念是如何支持这样的 零宽度断言概念? 什么是这样的?=s,零宽度断言的含义是在匹配时使用零字符的表达式。比如说这个例子, "foresight".sub(/sight/, 'ee') "foresight".sub(/(?<=s)ight/, 'ee') 匹配的是 foresight ^^^^^ foresight ^^^^ 因此,结果将是 foreee f
零宽度断言
。我突然想到一些问题-
- 为什么这样的名称
?零宽度断言
- 向前看和向后看概念是如何支持这样的
概念?零宽度断言
- 什么是这样的
,?=s
零宽度断言的含义是在匹配时使用零字符的表达式。比如说这个例子,
"foresight".sub(/sight/, 'ee')
匹配的是"foresight".sub(/(?<=s)ight/, 'ee')
foresight ^^^^^
因此,结果将是foresight ^^^^
foreee
但是在这个例子中,foresee
"foresight".sub(/sight/, 'ee')
因此,结果将是"foresight".sub(/(?<=s)ight/, 'ee')
foreee
零宽度断言的另一个示例是单词边界字符foresee
。例如,要匹配一个完整的单词,您可以尝试在单词周围加空格,例如 得到\b
但是您看到了在替换过程中,匹配空格是如何删除它的吗?使用单词边界可以解决此问题:flightdarkplight
"flight light plight".sub(/\blight\b/, 'dark')
匹配单词的开头或结尾,但实际上不匹配字符:宽度为零 对于您的问题,最简洁的答案可能是:Lookahead和Lookahead断言是一种零宽度断言。所有前向和后向断言都是零宽度断言。\b
以下是对您的示例的解释:irb(main):001:0> "foresight".sub(/(?!s)ight/, 'ee') => "foresee"
在上面,您是说,“匹配下一个字符不是irb(main):002:0> "foresight".sub(/(?!s)ight/, 'ee') => "foresee" irb(main):003:0> "foresight".sub(/ight/, 'ee') => "foresee"
,然后是s
”对于i
,这总是正确的,因为i
从来都不是i
,所以替换成功s
在上面,您是说,“匹配下一个字符是irb(main):002:0> "foresight".sub(/(?=s)ight/, 'ee') => "foresight"
,然后是s
”这永远都不是真的,因为i
永远都不是i
,所以替换失败s
irb(main):003:0> "foresight".sub(/(?<=s)ight/, 'ee') => "foresee"
上面已经解释过了。(这是正确的。)irb(main):003:0>“预见”。sub(/(?“预见”
irb(main):004:0>“预见”。sub(/(?“预见”
在这种情况下,“firefaight”将取代“firefee”,但不是“foresight”来“prevent”。零宽度断言很难理解,除非您意识到正则表达式匹配位置和字符 当你看到字符串“foo”时,你自然会读到三个字符。但是,还有四个位置,在这里用管道标记:“| f | o | o |”。“前看”或“后看”(又名“lookarounds”)与表达式前后字符的位置相匹配 零宽度表达式与其他表达式的区别在于零宽度表达式仅匹配(或“使用”)位置。例如:
将无法匹配“apple”,因为它尝试匹配“app”两次。但是/(app)apple/
将成功,因为前瞻只匹配“app”后面的位置。它实际上不匹配“app”字符,允许下一个表达式使用它们 环顾说明 正向前瞻:/(?=app)apple/
假设你是一名训练中士,正在执行一项检查。你从队伍的最前面开始,目的是要经过每个士兵,确保他们达到预期。但是,在这样做之前,你要一个接一个地向前看,确保他们已按财产顺序排好队。士兵的名字是“a”、“B”、“C”、“D”和“E”.(?=s)
。是的,它们都存在并说明了原因 负前瞻:/(?=ABCDE)…/.match('ABCDE')
你沿着生产线进行检查,最后站在D列兵处。现在你要向前看,确保另一家公司的“F”没有再次意外地进入错误的队形。(?!s)
。不,他这次没有滑倒,所以一切都很好 正向查找:/…(?!F)/.match('ABCDE')
(? 最后,军士长最后看了一眼,以确保列兵A和B没有再次交换位置(因为他们喜欢KP)。
/…(?。没有,他们没有,所以一切都很好
正则表达式从左到右匹配,并沿字符串移动一种“光标”。如果正则表达式包含类似
的正则字符,则表示:“如果光标前面有一个字母a
,请将光标向前移动一个字符,然后继续移动。否则,会出现问题;请后退并尝试其他操作。”因此,您可以说a
的“宽度”为一个字符 “零宽度断言”就是这样的:它断言关于字符串的某些内容(即,如果某些条件不成立,则不匹配),但它不会向前移动光标,因为它的“宽度”为零 您可能已经熟悉一些更简单的零宽度断言,如a
和^
。它们匹配字符串的开头和结尾。如果光标在看到这些符号时不在开头或结尾,正则表达式引擎将失败、备份并尝试其他操作。但它们实际上不会向前移动光标,因为它们不匹配字符;它们只检查光标所在的位置 Lookahead和Lookahead的工作方式相同。当正则表达式引擎尝试匹配它们时,它会在光标周围检查正确的模式是在它前面还是后面,但如果匹配,它不会移动光标$
1.9.3p125 :002 > 'jump june'.gsub(/ju(?=m)/, 'slu') => "slump june"
1.9.3p125 :002 > 'four flour'.gsub(/(?<=f)our/, 'ive') => "five flour"
1.9.3p125 :003 > 'child children'.gsub(/child(?!ren)/, 'kid') => "kid children"
考虑:1.9.3p125 :004 > 'foot root'.gsub(/(?<!r)oot/, 'eet') => "feet root"
这将匹配!正则表达式引擎如下所示:/(?=foo)foo/.match 'foo'
- 从字符串开头开始:
|foo
- 正则表达式的第一部分是
。这意味着:只有当(?=foo)
出现在光标后时才匹配。是吗?好的,是的,所以我们可以继续。但是光标不移动,因为这是零宽度。我们仍然有foo
<|foo
irb(main):002:0> "foresight".sub(/(?!s)ight/, 'ee') => "foresee" irb(main):003:0> "foresight".sub(/ight/, 'ee') => "foresee"
1.9.3p125 :001 > "foresight".sub(/(?<!s)ight/, 'ee') => "foresight"
- 从字符串开头开始: