带有组织模式文件的Python多行正则表达式

时间:2017-08-11 18:45:03

标签: python regex org-mode

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

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)

3 个答案:

答案 0 :(得分:2)

有一些可能性,包括非正则表达式解决方案 正如你特别要求的那样:

^\*\ 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:', '']}

这有一个缺点,即从例如也会使用* headline abc* headliner***。说实话,我在这里寻求regex解决方案。

答案 1 :(得分:1)

我想你可以这样做。仅匹配包含 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
      . 
 )*

答案 2 :(得分:1)

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

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

^\*\sheadline - &gt;众所周知这个项目是这样开始的。

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

:END:$ - &gt;它包括一行末尾的已知结束语句。

Working demo.