如何在%r<内进行负向回溯...Ruby 中>分隔的正则表达式?

How to do a negative lookbehind within a %r<…>-delimited regexp in Ruby?

提问人:Tyler Rick 提问时间:4/26/2019 最后编辑:Tyler Rick 更新时间:7/22/2019 访问量:230

问:

我喜欢分隔符,因为它可以很容易地发现正则表达式的开头和结尾,而且我不必转义任何 .但似乎它们有一个其他分隔符所没有的不可逾越的限制?%r<…>/

所有其他可以想象到的分隔符都可以正常工作:

/(?<!foo)/
%r{(?<!foo)}
%r[(?<!foo)]
%r|(?<!foo)|
%r/(?<!foo)/

但是当我尝试这样做时:

%r<(?<!foo)>

它给出了以下语法错误:

unterminated regexp meets end of file

好吧,它可能不喜欢它不是一对平衡的对,但你如何逃避它,让它喜欢它呢?

有什么需要逃避的吗?

根据 wikibooks.org

任何单个非字母数字字符都可以用作分隔符 。 通过使用此表示法,可以出现通常的字符串分隔符 “ 和 ' 在字符串中未转义,但当然是您选择的新分隔符 确实需要逃脱。%[including these], %?or these?, %~or even these things~

事实上,在这些示例中需要转义:

%r!(?<\!foo)!                                                             
%r?(\?<!foo)? 

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

%r<(?\<!foo)>

但这会产生以下错误:

undefined group option: /(?\<!foo)/

所以也许不需要/不允许逃跑wikibooks.org 列为例外之一:%<pointy brackets>

但是,如果您使用 或 作为分隔符,那么这些相同的分隔符 只要它们在平衡对中,就可以在字符串中显示为未转义%(parentheses), %[square brackets], %{curly brackets}%<pointy brackets>

平衡对有问题吗?

平衡对没有问题,只要您在正则表达式中做一些需要它们的事情,例如......

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

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

%r{(?<!foo\{)}                                                                  
%r[(?<!\[foo)]
%r<\<foo>

只是当你尝试在“组选项”(我猜这就是这里的字符分类)中间这样做时,它不喜欢它:<!(?

%r<(?\<!foo)>
# undefined group option: /(?\<!foo)/

那么,你如何做到这一点,让 Ruby 开心呢?(不更改分隔符)

结论

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

但问题仍然存在......

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

版本信息

这并不重要,因为这个语法可能没有改变,但我正在使用:

⟫ ruby -v
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]

参考:

正则表达式 Ruby 语法错误 正则表达式

评论

0赞 4/26/2019
你从不平衡中得到什么?是原始字符串表示法吗?%r<(?<=<)>%r
0赞 4/26/2019
从理论上讲,特殊对的解决方法是使用单个分隔符。因此,它需要平衡对(未转义)来确定结束分隔符的位置。否则它会带你过去。因为,这里没有魔法解析。.*>
1赞 4/26/2019
而且,如果你仔细想想,在正则表达式结构中,只有尖锐的那些被不配对地使用。所有其他货币对都是平衡的。我会避开那对<>
1赞 Tyler Rick 4/26/2019
很好,我会试一试!~
3赞 Cary Swoveland 4/26/2019
很少有人会遇到一个有趣、具有挑战性和表达得非常好的问题。干得好!

答:

2赞 user208769 7/22/2019 #1

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

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

%r<(?#{'<'}!foo)> == %r((?<!foo))

使用插值插入字符似乎有效。但鉴于有更好的选择,除非您打算将正则表达式拆分为多个部分,否则我会避免它......<