【问题标题】:Python multiline regex with org-mode files带有组织模式文件的 Python 多行正则表达式
【发布时间】:2017-08-11 18:45:03
【问题描述】:

使用正则表达式,我想从 Emacs 组织模式文件中提取某些部分,这些部分是简单的文本文件。这些 org 文件中的条目以 * 开头,有时这些条目确实具有属性。一个简短的例子可以在下面找到:

import re

orgfiletest = """
* headline 0
* headline 1
  :PROPERTIES:
  :KEY: lala
  :END:
* headline 2
* headline 3
  :PROPERTIES:
  :KEY: lblb
  :END:
"""

我想提取所有具有属性的条目;提取的条目应包括这些属性。所以,我想收到以下文字:

* headline 1
  :PROPERTIES:
  :KEY: lala
  :END:

* headline 3
  :PROPERTIES:
  :KEY: lblb
  :END:

我是这样开始的

re.findall(r"\*.*\s:END:", orgfiletest, re.DOTALL)

但这也包括headline 0headline 2,它们没有任何属性。我的下一次尝试是利用环视,但无济于事。任何帮助深表感谢!

适合我的更新/解决方案:

感谢所有帮助我找到解决方案的人!为了将来参考,我包含了一个更新的 MWE 和适用于我的正则表达式:

import re
orgfiletest = """
* headline 0
  more text 
* headline 1
  :PROPERTIES:
  :KEY: lala
  :END:
* headline foo 2
** bar 3
  :PROPERTIES:
  :KEY: lblb
  :FOOBAR: lblb
  :END:
* new headline
  more text
"""

re.findall(r"^\*+ .+[\r\n](?:(?!\*)\s*:.+[\r\n]?)+", orgfiletest, re.MULTILINE)

【问题讨论】:

    标签: python regex org-mode


    【解决方案1】:

    有几种可能性,包括非正则表达式解决方案。
    正如您特别要求的那样:

    ^\*\ headline\ \d+[\r\n] # look for "* headline digit(s) and newline
    (?:(?!\*).+[\r\n]?)+     # followed by NOT a newline at the beginning
                             # ... anything else including newlines afterwards
                             # ... at least once
    

    a demo on regex101.com(注意修饰符xm!)


    Python 中,这将是:
    import re
    
    rx = re.compile(r'''
                ^\*\ headline\ \d+[\r\n] 
                (?:(?!\*).+[\r\n]?)+
                ''', re.VERBOSE | re.MULTILINE)
    
    print(rx.findall(orgfiletest))
    


    非正则表达式方式可能是(使用itertools):
    from itertools import groupby
    
    result = {}; key = None
    for k, v in groupby(
            orgfiletest.split("\n"), 
            lambda line: line.startswith('* headline')):
        if k:
            item = list(v)
            key = item[len(item)-1]
        elif key is not None:
            result[key] = list(v)
    
    print(result)
    # {'* headline 1': ['  :PROPERTIES:', '  :KEY: lala', '  :END:'], '* headline 3': ['  :PROPERTIES:', '  :KEY: lblb', '  :END:', '']}
    

    这有一个缺点,即以 e.g. 开头的行* headline abc* headliner*** 也将被使用。老实说,我会在这里选择regex 解决方案。

    【讨论】:

    • 像魅力一样工作,非常感谢!只是出于好奇,还有哪些其他可能性,包括非正则表达式解决方案?
    • @BerndWeiss:抱歉,不在。更新了答案并添加了非正则表达式解决方案。
    • 再次感谢您的帮助!不过,我应该强调的是,在标题中可以找到除“标题”之外的其他词。我已经用适合我的解决方案更新了我的问题。
    【解决方案2】:

    我想你可以这样做。仅匹配包含 PROPERTIES

    的 rec

    (?ms)^\*(?:(?!^\*).)*?PROPERTIES(?:(?!^\*).)*

    https://regex101.com/r/oZcos0/1

    解释

     (?ms)                 # Inline modifiers:  Multi-line, Dot-all
     ^ \*                  # Start record: BOL plus *
     (?:                   # Minimal matching
          (?! ^ \* )            # Not a new record
          . 
     )*?
     PROPERTIES            # Up to prop
     (?:                   # Max matching up to begin new record
          (?! ^ \* )            # Not a new record
          . 
     )*
    

    【讨论】:

      【解决方案3】:

      尝试制作可读的正则表达式:

      ^\*\sheadline(?:(?!^\*\sheadline).)*:END:$
      

      ^\*\sheadline -> 已知项目是这样开始的。

      (?:(?!^\*\sheadline).)* -> 匹配任何内容,只要它不包括我们如何知道新项目开始。

      :END:$ -> 在行尾包含一个已知的结束语句。

      Working demo.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-26
        • 1970-01-01
        • 1970-01-01
        • 2017-06-21
        • 1970-01-01
        • 2011-05-18
        • 2015-11-21
        • 1970-01-01
        相关资源
        最近更新 更多