Look-ahead 和 Look-behind 概念如何支持 Ruby 正则表达式中的零宽度断言概念?

2023-11-27

我刚刚经历过这个概念Zero-Width Assertions从文档中。我的脑海中浮现出一些简单的问题——

  • 为什么这样的名字Zero-Width Assertions?
  • How the Look-ahead and look-behind概念支持这样的Zero-Width Assertions概念?
  • 什么这样的?<=s,<!s,=s,<=s- 图案内有 4 个符号指示?你能帮助我集中精力了解到底发生了什么吗

我还尝试了一些小代码来理解逻辑,但对这些代码的输出不太有信心:

irb(main):001:0> "foresight".sub(/(?!s)ight/, 'ee')
=> "foresee"
irb(main):002:0> "foresight".sub(/(?=s)ight/, 'ee')
=> "foresight"
irb(main):003:0> "foresight".sub(/(?<=s)ight/, 'ee')
=> "foresee"
irb(main):004:0> "foresight".sub(/(?<!s)ight/, 'ee')
=> "foresight"

有人可以帮我理解吗?

EDIT

在这里,我尝试了两个片段,其中一个具有“零宽度断言”概念,如下所示:

irb(main):002:0> "foresight".sub(/(?!s)ight/, 'ee')
=> "foresee"

另一个没有“零宽度断言”概念,如下所示:

irb(main):003:0> "foresight".sub(/ight/, 'ee')
=> "foresee"

上面两者都产生相同的输出,现在在内部如何两者regexp他们自己移动以产生输出——你能帮我想象一下吗?

Thanks


正则表达式从左到右匹配,并沿字符串移动某种“光标”。如果您的正则表达式包含常规字符,例如a,这意味着:“如果有一封信a在光标前面,将光标向前移动一个字符,然后继续。否则,就有问题了;备份并尝试其他事情。”所以你可能会这么说a其“宽度”为一个字符。

“零宽度断言”就是这样:它asserts有关字符串的某些内容(即,如果某些条件不成立,则不匹配),但它不会向前移动光标,因为它的“宽度”为零。

您可能已经熟悉一些更简单的零宽度断言,例如^ and $。它们匹配字符串的开头和结尾。如果光标在看到这些符号时不在开头或结尾,则正则表达式引擎将失败、备份并尝试其他操作。但它们实际上并没有向前移动光标,因为它们不匹配字符;他们只检查光标在哪里。

Lookahead 和 Lookbehind 的工作方式相同。当正则表达式引擎尝试匹配它们时,它会检查around光标以查看正确的模式是否位于其前面或后面,但如果匹配,则不会移动光标。

考虑:

/(?=foo)foo/.match 'foo'

这会匹配!正则表达式引擎是这样的:

  1. 从字符串的开头开始:|foo.
  2. 正则表达式的第一部分是(?=foo)。这意味着:仅匹配如果foo出现在光标后面。可以?嗯,是的,所以我们可以继续。但光标不动,因为这是零宽度。我们还有|foo.
  3. Next is f。有没有一个f在光标前面?是的,所以继续,并将光标移过f: f|oo.
  4. Next is o。有没有一个o在光标前面?是的,所以继续,并将光标移过o: fo|o.
  5. 同样的事情又把我们带到了foo|.
  6. 我们到达了正则表达式的末尾,没有任何失败,因此模式匹配。

特别是关于您的四个主张:

  • (?=...)是“前瞻”;它断言... does出现在光标后面。

    1.9.3p125 :002 > 'jump june'.gsub(/ju(?=m)/, 'slu')
     => "slump june" 
    

    “jump”中的“ju”匹配,因为接下来是“m”。但“june”中的“ju”后面没有“m”,所以就不用管它了。

    由于它不会移动光标,因此在其后面放置任何内容时必须小心。(?=a)b永远不会匹配任何内容,因为它检查下一个字符是a, then also检查是否same性格是b,这是不可能的。

  • (?<=...)是“后视”;它断言... does appear before光标。

    1.9.3p125 :002 > 'four flour'.gsub(/(?<=f)our/, 'ive')
     => "five flour" 
    

    “four”中的“our”匹配,因为它前面有一个“f”,但“flour”中的“our”前面有一个“l”,所以它不匹配。

    就像上面一样,你必须小心你所放的东西before it. a(?<=b)永远不会匹配,因为它检查下一个字符是a,移动光标,然后检查前一个字符是否为b.

  • (?!...)是“负前瞻”;它断言... does not出现在光标后面。

    1.9.3p125 :003 > 'child children'.gsub(/child(?!ren)/, 'kid')
     => "kid children"
    

    “child”匹配,因为接下来是一个空格,而不是“ren”。 “孩子”则不然。

    这可能是我最常用的一个;精细地控制接下来不能发生的事情会派上用场。

  • (?<!...)是“负向后看”;它断言... does not appear before光标。

    1.9.3p125 :004 > 'foot root'.gsub(/(?<!r)oot/, 'eet')
     => "feet root" 
    

    “foot”中的“oot”很好,因为它前面没有“r”。 “root”中的“oot”显然有一个“r”。

    作为附加限制,大多数正则表达式引擎要求...在这种情况下具有固定长度。所以你不能使用?, +, *, or {n,m}.

你也可以嵌套它们,或者做各种疯狂的事情。我使用它们主要是为了一次性使用,我知道我永远不需要维护,所以我手头没有任何现实世界应用程序的好例子;老实说,它们很奇怪,您应该首先尝试以其他方式做您想做的事情。 :)


事后思考:语法来自Perl正则表达式,其中使用了(?后面跟着许多扩展语法的各种符号,因为?其本身无效。所以<=本身并没有任何意义;(?<=是一个完整的标记,意思是“这是回顾的开始”。就像怎样+= and ++是单独的运算符,即使它们都以+.

不过,它们很容易记住:=表示向前看(或者实际上是“这里”),<表示向后看,并且!有其传统含义“不”。


关于你后面的例子:

irb(main):002:0> "foresight".sub(/(?!s)ight/, 'ee')
=> "foresee"

irb(main):003:0> "foresight".sub(/ight/, 'ee')
=> "foresee"

是的,它们产生相同的输出。这是使用前瞻的棘手之处:

  1. 正则表达式引擎尝试了一些方法,但没有成功,现在处于fores|ight.
  2. 它检查(?!s)。是人物after光标s?不,它是i!所以该部分匹配并且匹配继续,但是光标不动,我们还有fores|ight.
  3. 它检查ight. Does ight来到光标之后?嗯,是的,所以移动光标:foresight|.
  4. 我们完成了!

光标移到子字符串上ight,这就是完整的匹配,这就是被替换的内容。

Doing (?!a)b没用,因为你说:下一个字符must not be a,和它must be b。但这与仅匹配相同b!

这有时很有用,但您需要更复杂的模式:例如,(?!3)\d将匹配任何不是 3 的数字。

这就是你想要的:

1.9.3p125 :001 > "foresight".sub(/(?<!s)ight/, 'ee')
 => "foresight" 

这断言s不来before ight.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Look-ahead 和 Look-behind 概念如何支持 Ruby 正则表达式中的零宽度断言概念? 的相关文章

  • 正则表达式 - 检查输入是否仍有机会匹配

    我们有这样的正则表达式 var regexp one two three 所以只有像这样的字符串 one two three or one two three four or one twotwo three 等会匹配它 但是 如果我们有类
  • 仅在大括号外的空格上分割字符串

    我是正则表达式新手 我需要一些帮助 我阅读了一些与此问题类似的主题 但我不知道如何解决它 我需要在不在一对大括号内的每个空格上分割一个字符串 大括号外的连续空格应被视为单个空格 TEST test test test test test t
  • 使用解析将 ** 运算符更改为幂函数?

    我的要求是将 运算符更改为幂函数 例如 1 Input B 2 Output power B 2 2 B 2 T 2 X Output power B 2 我写了下面的正则表达式来解决这个问题 rx r a zA Z0 9 a zA Z0
  • 从类内部调用属性访问器方法[重复]

    这个问题在这里已经有答案了 我正在尝试调用我的类属性编写器之一 但由于某种原因它永远不会被调用 下面是一些代码 可以使这一点更清楚 class Test attr reader test def test val puts Called t
  • Rails 3 - “无法解析 Yaml”

    我不知道我做错了什么 我尝试运行 rails c 但它只是给了我一个错误 10 分钟前它还在工作 C Ruby192 lib ruby 1 9 1 psych rb 148 in parse couldn t parse YAML at l
  • 使用正则表达式如何从十进制数中删除尾随零

    我需要编写一些正则表达式 它接受一个数字并删除小数点后的所有尾随零 语言是 Actionscript 3 所以我想写 var result String theStringOfTheNumber replace the regex 例如 3
  • 文件名的正则表达式模式

    如果文件名符合以下条件 用户可以将文件放入服务器 它必须以 abc 开头 然后是一个点和一个数字 Valid file names abc 2344 abc 111 Invalid abcd 11 abc ab12 正则表达式是什么 我不能
  • 带有附加参数的redirect_to

    我是一个菜鸟 redirect to users url notice Succeed p p 然后我添加一个message它失败了 redirect to users url notice Succeed message test p p
  • 如何使用正则表达式匹配模式的最后一次出现

    我有一个像这样的字符串 token1 token2 我要匹配 token2 使用正则表达式 它应该匹配的其他可能的情况是 token1 应该匹配 最后一个 token1 应该匹配 最后一个 token1 token2应该匹配 token2
  • 如何编写一个在安装 RubyGem 时调用的钩子?

    我想编写一个 Ruby 片段 当我的 Gem 首次安装时运行 sudo gem install mygem 能做到吗 看起来并没有真正支持 我发现了一个 post install message 属性 您应该能够在 gem 规范中设置该属性
  • Ruby mp3 Id3 解析

    目前我正在从事一个音乐项目 处理用户 mp3 上传 问题是我找不到适用于所有文件的 id3 库 我努力了id3 ruby and Mp3Info库 但它们都没有给我一致正确的结果 例如 最常见的问题 错误的流参数 比特率和采样率 有时是持续
  • 使用先前的反向引用作为命名捕获组的名称

    有没有办法使用对先前捕获组的反向引用作为捕获组的名称命名捕获组 这可能不可能 如果不可能 那么这就是一个有效的答案 下列 data description some description preg match data matches p
  • RSpec 请求规范发布一个空数组

    我目前正在 Rails 中开发 API 端点 如果我需要的数据无效 我想确保端点响应具有正确的错误状态 我需要一个 id 数组 无效值之一是空数组 Valid vendor district ids 2 4 5 6 Invalid vend
  • REgex从oracle中的字符串中获取数字

    我有以下格式的字符串 阿克拉姆 88 jamesstree 20140418 阿克兰 8 约翰街 20140418 阿克兰 888 johnstreet 20140418 现在我只想检索 88 8 和 888 值 我为此编写了以下查询 SU
  • ||= 是什么意思? [复制]

    这个问题在这里已经有答案了 我的应用程序控制器中有一个受保护的方法 def current user current user User find by id session user id end 我想知道什么 方法 我一直在努力寻找和找
  • 正则表达式拆分数字和字母组,不带空格

    如果我有一个像 11E12C108N 这样的字符串 它是字母组和数字组的串联 如何在中间没有分隔符空格字符的情况下分割它们 例如 我希望分割结果为 tokens 0 11 tokens 1 E tokens 2 12 tokens 3 C
  • 回滚后是否应该删除迁移

    我对 ruby 和 Rails 相当陌生 刚刚开始了解迁移 我的问题是回滚后删除迁移的最佳实践或正确时间是什么 到目前为止 我读到的内容是回滚后是否删除迁移的观点问题 但是在团队中工作时删除迁移是否有任何重大影响 以及保留迁移文件相对于删除
  • 在python中,如何仅搜索所选子字符串之前的一个单词

    给定文本文件中的长行列表 我只想返回紧邻其前面的子字符串 例如单词狗 描述狗的单词 例如 假设有这些行包含狗 hotdog big dog is dogged dog spy with my dog brown dogs 在这种情况下 期望
  • 我必须使用什么加密程序来通过 HTTP 协议发送加密的“电子邮件”和“密码”值?

    我正在使用 Ruby on Rails 3 我想通过 HTTP 协议发送 电子邮件 和 密码 值 我知道 我不应该 但我需要 我需要从发送用户凭据我的客户申请到一个我的服务应用 我可以使用公共和私人RSA密钥来实现这一点 但如果是这样 我不
  • Python 的“zip”内置函数的 Ruby 等价物是什么?

    Ruby 是否有与 Python 内置函数等效的东西zip功能 如果不是 做同样事情的简洁方法是什么 一些背景信息 当我试图找到一种干净的方法来进行涉及两个数组的检查时 出现了这个问题 如果我有zip 我可以写这样的东西 zip a b a

随机推荐