【问题标题】:regular expression greedy on left side only (.net)正则表达式仅在左侧贪婪(.net)
【发布时间】:2023-04-10 15:57:01
【问题描述】:

我正在尝试捕获两个字符串之间的匹配项。

例如,我正在查找出现在 Q 和 XYZ 之间的所有文本,使用“最快”匹配(不继续向外扩展)。这个字符串:

马戏团 Q 你好 Q SOMETEXT XYZ 今天是 XYZ 好的 XYZ

应该返回:

Q SOMETEXT XYZ

但相反,它返回:

你好 Q SOMETEXT XYZ

这是我正在使用的表达式: Q.*?XYZ

它向左走得太远了。当我在星号后使用问号时,它在骑行方面工作正常。我怎样才能对左侧做同样的事情,并在我击中第一个左 Q 后停止,使其与右侧的工作方式相同?我已经尝试过 http://msdn.microsoft.com/en-us/library/az24scfc.aspx 中的问号和其他符号,但有些东西我只是想不通。

我是一个正则表达式新手,因此我们将不胜感激!

【问题讨论】:

    标签: c# .net regex regex-greedy non-greedy


    【解决方案1】:

    贪婪的概念只适用于右侧。

    要使表达式仅匹配 XYZ 之前的最后一个 Q,使其不匹配它们之间的 Q:

    Q[^Q]*?XYZ
    

    【讨论】:

      【解决方案2】:

      嗯,非贪婪匹配是有效的——它得到满足正则表达式的最短字符串。您必须记住的是,regex 是一个从左到右的过程。所以它匹配第一个 Q,然后得到最短的字符数,然后是 XYZ。如果您希望它不超过任何 Q,则必须使用否定字符类:

      Q[^Q]*?XYZ
      

      [^Q] 匹配任何不是 Q 的字符。请注意,这仅适用于单个字符。如果您的开头分隔符是多个字符,则必须以不同的方式进行。为什么?好吧,取分隔符'PQR',字符串是

      foo PQR bar XYZ 
      

      如果您尝试使用之前的正则表达式,但您将字符类扩展为:

      PQR[^PQR]*?XYZ
      

      然后你会得到

      'PQR bar XYZ'
      

      正如你所料。但是如果你的字符串是

      foo PQR Party Time! XYZ 
      

      你不会得到任何匹配。这是因为 [] 描述了一个“字符类”——它只匹配一个字符。使用这些类,您可以匹配一系列字符,只需列出它们。

      th[ae]n
      

      将匹配“than”和“then”,但不匹配“thin”。在开头放置一个克拉 ('^') 会否定类 - 意思是“匹配除这些字符之外的任何内容” - 所以通过将我们的单字符分隔符转换为 [^PQR],而不是说“不是 'PQR'”,你'重新说“不是'P','Q'或'R'”。如果你愿意,你仍然可以使用它,但前提是你 100% 确定你的分隔符中的字符只会在你的分隔符中。如果是这种情况,使用贪婪匹配会更快,并且只否定定界符的第一个字符。正则表达式是:

      PQR[^P]*XYZ 
      

      但是,如果你不能保证,那么匹配:

      PQR(?:.(?!PQR))*?XYZ
      

      Regex 不直接支持负字符串匹配(因为它是不可能定义的,当你想到它时),所以你必须使用 negative lookahead

      (?!PQR)
      

      就是这样一个前瞻性。意思是“断言接下来的几个字符不是这个内部的正则表达式”,不匹配任何字符,所以

      .(?!PQR)
      

      匹配任何没有后跟 PQR 的字符。把它打包成一个组,这样你就可以懒洋洋地重复它,

      (.(?!PQR))*?
      

      并且您匹配“不包含我的分隔符的字符串”。我唯一做的就是添加一个 ?: 使其成为非捕获组。

      (?:.(?!PQR))*?
      

      根据您用于解析正则表达式的语言,它可能会尝试单独传回每个匹配的组(对于查找和替换很有用)。这会阻止它这样做。

      快乐的正则表达式!

      【讨论】:

      • 非常感谢您的回答以及详细的解释。我将不得不对组和非捕获组进行一些调查,因为我真的不知道它们是什么。虽然我倾向于使用您的第二个示例,但由于我有多个字符,但我确实注意到您的第一个示例似乎仍然适用于多个字符。如果我用多个第一种方式做,那以后会咬我吗?再次感谢!
      • @Josh 它会排序的工作。所以如果你的分隔符是 PQR 并且你的字符串是 'foo PQR bar XYZ' - 他们你会得到'PQR bar XYZ',正如预期的那样。但如果你的字符串是 'foo PQR Party Time! XYZ' 你不会得到任何匹配。我会更新我的答案来解释原因。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      相关资源
      最近更新 更多