【问题标题】:Non greedy dotall regex in PythonPython中的非贪婪dotall正则表达式
【发布时间】:2014-07-31 09:33:56
【问题描述】:

我需要解析用 PHP 编写的方法的注释。我写了一个正则表达式(见下面的简化示例)来搜索它们,但它没有按预期工作。它不是匹配/***/ 之间的最短文本部分,而是匹配源代码的最大数量(以前的方法带有注释)。我确定我使用的是正确的.*? 非贪婪版本的*,并且我没有发现任何证据表明 DOTALL 将其关闭。请问可能是哪里出了问题?谢谢你。

p = re.compile(r'(?:/\*\*.*?\*/)\n\s*public', re.DOTALL)
methods = p.findall(text)

【问题讨论】:

  • 对我来说很好。删除re.DOTALL 是否会使其突然再次起作用?
  • 您能include some sample data for text in a triple-quoted string,这样我们可以将示例复制粘贴到解释器会话中,然后自己查看问题吗? (如果将示例复制粘贴到解释器会话中,请确保示例数据显示问题。)
  • 举个例子会更好。
  • 不,没有re.DOTALL,它根本无法工作 - 什么也没找到。
  • \s 也匹配 \n 字符。

标签: python regex search non-greedy


【解决方案1】:

我认为你正在尝试得到这个,

>>> text = """ /** * comment */ class MyClass extens Base { /** * comment */ public function xyz """
>>> m = re.findall(r'\/\*\*(?:(?!\*\/).)*\*\/\s*public', text, re.DOTALL)
>>> m
['/** * comment */ public']

如果您不想在决赛中使用public,请使用下面的正则表达式,该正则表达式使用正向预测,

>>> m = re.findall(r'\/\*\*(?:(?!\*\/).)*\*\/(?=\s*public)', text, re.DOTALL)
>>> m
['/** * comment */']

【讨论】:

  • 很抱歉让您感到困惑。当public 之前没有注释时,我必须找到public function xyz 文本,因为我也解析方法头。
  • 请在您的问题中发布实际输入。
  • 感谢您的愿意,user3853423已经回答了我的问题。
  • 我想他只是解释了我的正则表达式而已
【解决方案2】:

正则表达式引擎从左到右解析。惰性量词将尝试从当前匹配位置开始尽可能少地匹配,但它不能将匹配开始向前推进,即使这会减少匹配的文本数量。这意味着不是从public 之前的最后一个/** 开始,而是从第一个/** 匹配到附加到public 的下一个*/

如果您想从评论中排除 */,您需要将 . 与前瞻断言组合在一起:

(?:(?!\*/).)

(?!\*/) 断言我们匹配的字符不是*/ 序列的开始。

【讨论】:

  • 应该是这个样子? p = re.compile(r'(?:/\*\*(?!\*/).*?\*/)\n\s*public', re.DOTALL)
  • @user3853423:是的,我刚刚意识到我忘了提到断言必须与. 分组,所以*? 每次都会运行断言。它应该看起来像r'(?:/\*\*(?:(?!\*/).)*?\*/)\n\s*public'。顺便说一句,这个正则表达式很混乱,使用verbose mode 可能是个好主意。
  • 我现在正在使用r'(?:/\*\*(?:(?!\*/).)*?\*/)\s*public',但我发现我找不到没有注释的方法(示例输入中省略了第二条注释)尽管有 ?: 在正则表达式的开头.请问怎么了?
  • @user3853423:我认为这就是你想要的。 ?: 不代表可选;这意味着不捕获。如果你想让它成为可选的,在组后面加上一个?
【解决方案3】:

你应该可以使用这个:

\/\*\*([^*]|\*[^/])*?\*\/\s*public

这将匹配任何不是星号 (*) 的符号,如果是星号,则不允许其后跟正斜杠。这意味着它应该只捕获在公开之前而不是更早关闭的 cmets。

示例:http://regexr.com/398b3

解释:http://tinyurl.com/lcewdmo

免责声明:如果评论中包含*/,这将不起作用。

【讨论】:

    【解决方案4】:
    # Some examples and assuming that the annotation you want to parse
    # starts with a /** and ends with a */.  This may be spread over
    # several lines.
    
    text = """
    /**
     @Title(value='Welcome', lang='en')
     @Title(value='Wilkommen', lang='de')
     @Title(value='Vitajte', lang='sk')
     @Snippet
        ,*/
    class WelcomeScreen {}
    
       /** @Target("method") */
      class Route extends Annotation {}
    
    /** @Mapping(inheritance = @SingleTableInheritance,
        columns = {@ColumnMapping('id'), @ColumnMapping('name')}) */
    public Person {}
    
    """
    
    text2 = """ /** * comment */
    CLASS MyClass extens Base {
    
    /** * comment */
    public function xyz
    """
    
    
    import re
    
    # Match a PHP annotation and the word following class or public
    # function.
    annotations = re.findall(r"""/\*\*             # Starting annotation
                                                   # 
                                (?P<annote>.*?)    # Namned, non-greedy match
                                                   # including newline
                                                   #
                                 \*/               # Ending annotation
                                                   #
                                 (?:.*?)           # Non-capturing non-greedy
                                                   # including newline
                     (?:public[ ]+function|class)  # Match either
                                                   # of these
                                 [ ]+              # One or more spaces
                                 (?P<name>\w+)     # Match a word
                             """,
                             text + text2,
                             re.VERBOSE | re.DOTALL | re.IGNORECASE)
    
    for txt in annotations:
         print("Annotation: "," ".join(txt[0].split()))
         print("Name: ", txt[1])
    

    【讨论】:

      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-22
      相关资源
      最近更新 更多