【问题标题】:Variable length look-behind可变长度后视
【发布时间】:2014-08-29 07:51:43
【问题描述】:

是否有任何优雅的解决方案来构建可变长度的后视正则表达式,例如这个?

/(?<=eat_(apple|pear|orange)_)today|yesterday/g;

似乎 Perl 有一个非常令人印象深刻的正则表达式引擎,可变长度的后视会非常有趣。有没有办法让它发挥作用,还是我应该忘记这个坏主意?

【问题讨论】:

  • 您是否只想匹配todayyesterday 之后的eat_appleeat_peareat_orange
  • /((?&lt;=eat_apple_)|(?&lt;=eat_pear_)|(?&lt;=eat_orange_))today|yesterday/g 今天当然可以做到这一点,但它远没有我们想要的优雅。真正的限制是具有 *s 和 +s 或其他广泛长度范围的匹配器。我的理解是 .NET 的实现通过反转模式和字符串来解决这个问题。

标签: regex perl


【解决方案1】:

使用\K 作为特例。

这是一个可变长度的正向回溯断言:

/eat_(?:apple|pear|orange)_\Ktoday|yesterday/g

或者,您可以单独列出您的后向断言:

/(?:(?<=eat_apple_)|(?<=eat_pear_)|(?<=eat_orange_))today|yesterday/g

但是,我建议这将是一个可能会使用该功能的罕见问题,但不能重新考虑使用其他更常见的正则表达式功能的组合。

换句话说,如果您遇到特定问题,请随时在此处分享,我相信有人可以提出不同(也许更好)的方法。

【讨论】:

  • Nit: \K 不是可变长度的后视。它的意思是“保留”,并且不包括在它之前的任何内容,不包括在$&amp;(匹配的字符串)中。也就是说,\K 可用于模拟可变长度的正向后视,所以 +1。
【解决方案2】:

怎么样:

(?:(?<=eat_apple_)|(?<=eat_pear_)|(?<=eat_orange_))(today|yesterday)

有点难看,但很管用。

【讨论】:

  • +1 对于小型有限列表来说,这绝对是一个很好的解决方法。
  • +1 和(?&lt;=eat_apple_|eat_pear_|eat_orange_)(today|yesterday)(没有带括号的子模式)在 perl 中不起作用?还是固定长度:see example
  • @Jonny5:不,长度不相等。
【解决方案3】:

您可以使用前瞻而不是后瞻:

/(?:eat_(apple|pear|orange)_)(?=today|yesterday)/g

一般来说,有另一种方式来描述看似天真地需要后视的事物。

【讨论】:

    【解决方案4】:

    今天找到的博文,在 #regex @ irc.freenode.org 上与我链接:

    http://www.drregex.com/2019/02/variable-length-lookbehinds-actually.html

    本文介绍了如何在 PCRE 中进行可变宽度后视。

    那么解决办法是:

    /(?=(?=(?'a'[\s\S]*))(?'b'eat_(?:apple|pear|orange)_(?=\k'a'\z)|(?<=(?=x^|(?&b))[\s\S])))today|yesterday/g
    

    https://regex101.com/r/9DNpFj/1

    【讨论】:

      【解决方案5】:

      替代解决方案 - 反转字符串并改用前瞻。将模式词反过来写可能看起来很难看,但当其他一切都失败时,这是一种选择。

      【讨论】:

        【解决方案6】:

        Perl v5.30 在正则表达式引擎知道长度为 255 个字符或更少的情况下添加了 experimental variable-width lookbehinds(例如,没有无限量词)。

        现在可以了:

        use v5.30;
        use experimental qw(vlb);
        
        $_ = 'eat_apple_today';
        say "Matched!" if /(?<=eat_(apple|pear|orange)_)today|yesterday/g;
        

        【讨论】:

          【解决方案7】:

          对我有用的解决方案:
          暂时将长度可变的任何内容固定为长度。

          在这种情况下:
          将所有 'eat_apple's、'eat_pear's 和 'eat_orange's 更改为 eat_fruit 之类的内容,然后以可接受的固定长度后视运行您正在考虑的表达式。尽管它需要两次传递和一些内存,但我发现代码方式更易于阅读,并且可能比其他一些解决方案更快。

          【讨论】:

            猜你喜欢
            • 2021-08-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-02-18
            • 1970-01-01
            • 2014-07-27
            • 2020-11-20
            相关资源
            最近更新 更多