如何在Ruby中用%r <…>分隔的正则表达式中进行负向查找?

Tyl*_*ick 11 ruby regex syntax syntax-error regex-lookarounds

我喜欢%r<…>定界符,因为它使查找正则表达式的开始和结束变得非常容易,而且我也不必转义任何内容/。但是,它们似乎有其他定界符没有的无法克服的限制?

可以想象的所有其他定界符都可以正常工作:

/(?<!foo)/
%r{(?<!foo)}
%r[(?<!foo)]
%r|(?<!foo)|
%r/(?<!foo)/
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这样做时:

%r<(?<!foo)>
Run Code Online (Sandbox Code Playgroud)

它给出以下语法错误:

unterminated regexp meets end of file
Run Code Online (Sandbox Code Playgroud)

好吧,这可能不一样,它不是一个平衡的对,但是你怎么逃避它,使得它喜欢吗?

是否需要逃脱?

根据wikibooks.org

任何单个非字母数字字符都可以用作分隔符 %[including these], %?or these?, %~or even these things~。通过使用这种表示法,通常的字符串定界符“和”可以出现在未转义的字符串中,但是当然您必须转义选择的新定界符。

实际上,在以下示例中需要转义:

%r!(?<\!foo)!                                                             
%r?(\?<!foo)? 
Run Code Online (Sandbox Code Playgroud)

但是,如果那是唯一的问题,那么我应该能够像这样逃脱它并使它起作用:

%r<(?\<!foo)>
Run Code Online (Sandbox Code Playgroud)

但这会产生此错误:

undefined group option: /(?\<!foo)/
Run Code Online (Sandbox Code Playgroud)

因此,也许逃避是没有必要/允许?wikibooks.org确实将以下情况%<pointy brackets>列为例外之一:

但是,如果使用 %(parentheses), %[square brackets], %{curly brackets}%<pointy brackets>作为分隔符,然后那些相同的分隔符可以出现转义,因为它们中的字符串,只要在平衡

平衡对有问题吗?

只要您在Regexp中执行需要平衡对的操作即可,例如...

%r{(?<!foo{1})}   # repetition quantifier
%r[(?<![foo])]    # character class
%r<(?<name>foo)>  # named capture group
Run Code Online (Sandbox Code Playgroud)

但是,如果您需要在正则表达式中插入左侧的定界符({,[或<),该怎么办?逃脱吧?Ruby 多数时候似乎对逃脱的不平衡分隔符没有问题...

%r{(?<!foo\{)}                                                                  
%r[(?<!\[foo)]
%r<\<foo>
Run Code Online (Sandbox Code Playgroud)

只是当您尝试在不喜欢它的“组选项”(我猜这是<!字符在这里分类)的中间进行操作(?时:

%r<(?\<!foo)>
# undefined group option: /(?\<!foo)/
Run Code Online (Sandbox Code Playgroud)

那么,您该如何做才能让Ruby开心呢?(不更改定界符)

结论

解决方法很简单。我将更改此特定正则表达式,使其仅使用其他名称%r{…}代替。

但是问题仍然存在...

  1. 真的没有办法逃脱<这里吗?
  2. 是否确实存在某些正则表达式,使用某些分隔符根本无法编写这些正则表达式%r<…>
  3. %r<…>唯一存在此问题的正则表达式定界符对(其中某些正则表达式在使用时无法编写)。如果您知道带有%r{…}/ 的类似示例%r[…],请共享!

版本信息

并不是很重要,因为此语法可能没有更改,但是我正在使用:

? ruby -v
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
Run Code Online (Sandbox Code Playgroud)

参考:

use*_*769 2

正如其他人所提到的,这似乎是基于此字符与其他配对边界的不同之处的疏忽。

至于“真的没有办法逃离这里吗?” 有一种方法...但你不会喜欢它:

%r<(?#{'<'}!foo)> == %r((?<!foo))
Run Code Online (Sandbox Code Playgroud)

使用插值插入<字符似乎可行。但考虑到有更好的选择,我会避免它,除非你打算将正则表达式分成几个部分......