Regex环顾四周-Java

Regex环顾四周-Java,regex,lookahead,lookaround,Regex,Lookahead,Lookaround,我继承了一些正则表达式,并试图理解它为什么匹配某些模式。下面的正则表达式是基于积极的前瞻断言和匹配文本,如熊格里尔的插曲。这是有道理的。但它也匹配插曲后面跟着熊格里尔斯的文本,例如插曲熊格里尔斯。我在正则表达式中没有看到任何向后看的参考。最后的*?是不是让它向后看 ^(?=.*?bear grylls)(?=.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere)).*? 这解释了它的作用。 要修改,它取决于您要执行的操作 这

我继承了一些正则表达式,并试图理解它为什么匹配某些模式。下面的正则表达式是基于积极的前瞻断言和匹配文本,如
熊格里尔的插曲
。这是有道理的。但它也匹配
插曲
后面跟着
熊格里尔斯
的文本,例如
插曲熊格里尔斯
。我在正则表达式中没有看到任何向后看的参考。最后的
*?
是不是让它向后看

^(?=.*?bear grylls)(?=.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere)).*?

这解释了它的作用。
要修改,它取决于您要执行的操作

这就是它目前所做的-

 # ^(?=.*?bear\ grylls)(?=.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere)).*?

 ^                             # Beginning of string
 (?=                           # Look ahead
      .*?                           # Ungreedy, any number of characters
      bear\ grylls                  # Must be 'bear grylls' somewhere
 )                             # End lookahead
 (?=                           # Look ahead
      .*?                           # Ungreedy, any number of characters
      (                             # (1 start), Must be one of these somewhere
           \b nbc \b 
        |  reality
        |  episode
        |  show
        |  watch
        |  series
        |  season
        |  premiere
      )                             # (1 end)
 )                             # End lookahead
 .*?                           # Assertions passed tests, now match the entire string
我会将其修改为此,以获得更好的功能-

 # (?s)^(?=.*\bbear\ grylls\b)(?=.*\b(nbc|reality|episode|show|watch|series|season|premiere)\b).*

 (?s)                          # Dot all modifier
 ^                             # Beginning of string
 (?=                           # Look ahead
      .*                            # Greedy, any number of characters
      \b bear\ grylls \b            # Must be 'bear grylls' 
 )                             # End lookahead
 (?=                           # Look ahead
      .*                            # Greedy, any number of characters
      \b 
      (                             # (1 start), Must be one of these
           nbc 
        |  reality
        |  episode
        |  show
        |  watch
        |  series
        |  season
        |  premiere
      )                             # (1 end)
      \b 
 )                             # End lookahead
 .*                            # Assertions passed tests, now match the entire string

我建议在格式化和创建自动注释的地方使用。

所有向前看和向后看断言
(?=…)
(?!…)
(?)不使用文本。它不会将指针提前到当前位置,这是匹配某些文本时的正常行为

由于它不会推进索引,因此可以使用此属性检查文本的多个属性,否则,如果不向前看,很难将这些属性组合成单个表达式

在您的例子中,正则表达式检查是否存在字符串
bear grylls
,然后在第二个前瞻中检查是否存在任何字符串

如果没有前瞻性,正则表达式将变成:

^.*?bear grylls.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere)|^.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere).*?bear grylls
由于
bear grylls
可以位于列表中任何字符串的前面或后面,因此需要交替检查这两种情况。干问题可以通过字符串连接来解决,但如果不可用,人们将很难进行维护

这也是密码验证中经常使用的一种技术,其中可能存在多个条件,例如至少一个字母表、至少一个数字、至少一个特殊字符、一行中没有3个相同的字符等。如果要编写一个表达式来检查上述所有属性,则会非常混乱rtion允许您在一个表达式中填充所有内容,而不会使正则表达式变得不可理解和不可维护


就我个人而言,我不太喜欢这种方法,因为将所有内容都塞进一个正则表达式是没有意义的,除非您受到工具的限制,并且不允许运行多个正则表达式。我们只需创建两个正则表达式,然后针对每个正则表达式测试字符串。性能大致相同,因为在正则表达式中完成的工作量相同事实上,我相信大多数引擎都会在上面的正则表达式中重新扫描字符串两次。

我重写了原始正则表达式,这可以得到您想要的结果

^(?=.*?bear grylls).+(?=.*?(\bnbc\b|reality|episode|show|watch|series|season|premiere)).*?
它与前一个非常相似。唯一的区别是我在两个积极的前瞻性断言之间添加“+”,这将强制执行这两个部分的顺序,例如,“bear grylls插曲”将有积极的结果,而“Spice bear grylls”不会


如果没有这一点,这两个先行断言将不会有任何序列首选项。基本上,它们是完全相等的。

看一看,这在您键入正则表达式时为正则表达式提供了正确的解释。这不会像您认为的那样做。
^(?=.*bear grylls)
仍然匹配字符串中的任何位置。感谢NHAHDH,这澄清了关于位置的混淆。如果我理解正确,向前看比第二个选项更便宜。如果它不正确,请纠正我。@KaushalPatel:哪一个第二个选项?如果您谈论的是长正则表达式而没有向前看,那么它可能是正确的。但是如果您谈论的是如果不使用多个正则表达式,则两者应该大致相同。谢谢Sln。如何将.?*替换为。*帮助?贪婪匹配不是比懒惰匹配更昂贵吗?它便宜很多。在断言中,如果可以,请避免使用此
*?
构造。