【问题标题】:Unable to get my Ruby negative look ahead regex to work properly无法让我的 Ruby 否定前瞻正则表达式正常工作
【发布时间】:2017-10-08 07:12:27
【问题描述】:

我使用的是 Ruby 2.4。我想在字符串中搜索一个单词,但前提是它之前没有另一个单词。我想我可以使用这种消极的前瞻,如下所示,但是如果“bad”这个词在“apple”之前,我不想完成匹配,我仍然会得到“bad apple”这个短语”。 “bad”这个词和“apple”这个词之间只有一个空格,这并不是给定的。

2.4.0 :014 > word_regex = /(?!.*bad)(^|\s)#{Regexp.escape(word)}(\s|$)/i
 => /(?!.*bad)(^|\s)apple(\s|$)/i
2.4.0 :015 > "good apple".match(word_regex)
 => #<MatchData " apple" 1:" " 2:"">
2.4.0 :016 > "bad apple".match(word_regex)
 => #<MatchData " apple" 1:" " 2:"">

我还缺少什么?

【问题讨论】:

  • 我认为你想要一个消极的后视,例如(?&lt;!bad)。见SO docs
  • badapple 之间可以有任意数量的空格吗? Ruby 中的lookbehind 是固定宽度的,/(^|(?&lt;!\bbad)\s)#{Regexp.escape(word)}(?!\S)/i 可能无法在所有情况下正常工作。实际上,您使用空格作为单词边界这一事实暗示了您可以在此处不使用正则表达式。
  • 你可能仍然使用前瞻,但表达式看起来会更难看:(^\s*|\s(?!bad\s)\S+\s+)apple(?!\S)

标签: ruby regex lookahead negative-lookahead


【解决方案1】:

但是,等等,负前瞻可以是可变长度的!

R = /
    \b                 # match word break
    #{'apples'.reverse} # match 'elppa'
    \b                 # match word break
    (?!                # begin a negative lookahead
      \s+              # match one or more whitespaces
      #{'bad'.reverse} # match 'dab'
      \b               # match word break
    )                  # close negative lookaheaad
    /ix                # case-indifferent and free-spacing regex definition modes
#=> /
    \b                 # match word break
    elppa              # match 'selppa'
    \b                 # match word break
    (?!                # begin a negative lookahead
      \s+              # match one or more whitespaces
      dab              # match 'dab'
      \b               # match word break
    )                  # close negative lookaheaad
    /x

def avoid_bad_apples(str)
  str.reverse.match? R
end

avoid_bad_apples("good apples")           #=> true
avoid_bad_apples("Simbad apples")         #=> true
avoid_bad_apples("bad pears")             #=> false
avoid_bad_apples("bad apples")            #=> false
avoid_bad_apples("bad    apples")         #=> false
avoid_bad_apples("good applesauce")       #=> false
avoid_bad_apples("Very bad apples. BAD!") #=> false

【讨论】:

    【解决方案2】:

    考虑像这样(?&lt;!bad\s)apple 使用否定的lookbehind 仅当它前面没有bad 时才会查​​找apple。注意bad后面的空格。

    Regex101 Demo

    【讨论】:

    • @WiktorStribiżew:我知道先生。但由于 OP 没有提到多个空格,我假设它只有一个。
    • 不过,Wiktor 是对的。我想简化我的例子,所以我只放了一个空格,但是当我尝试多个空格 - /(?
    • @Dave:是的,那是因为不支持固定宽度的lookbehind。请根据多个空间要求更新您的帖子。
    • @engineersmnky:当然可以对字符串进行预处理。这仍然不是一个通用的解决方案(如果两个词之间可以有标点符号或符号怎么办?),但对于当前场景来说是一种潜在的解决方法。
    【解决方案3】:

    我试过了,它就像@sagarpandy82 所说的那样进行了回顾

    word_regex = /(?<!bad)(^|\s)#{Regexp.escape("apple")}(\s|$)/i
    a = "good apple".match(word_regex)
    b = "bad apple".match(word_regex)
    

    【讨论】:

      猜你喜欢
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2015-09-13
      • 2014-03-31
      • 1970-01-01
      相关资源
      最近更新 更多