2017-08-11 53 views
1

使用正則表達式,我想從Emacs組織模式文件,這是簡單的文本文件中提取某些部分。這些組織文件中的條目以*開頭,有時這些條目具有屬性。一個簡單的例子可以在下面找到:Python多行正則表達式與組織模式文件

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) 

回答

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解決方案。

+0

工程就像一個魅力,非常感謝!出於好奇,包括非正則表達式解決方案在內的其他可能性是什麼? –

+0

@BerndWeiss:對不起,離開了。更新了答案並添加了非正則表達式解決方案。 – Jan

+0

再次感謝您的幫助!不過,我應該強調的是,在標題中可以找到比「標題」更多的詞。我已經用適合我的解決方案更新了我的問題。 –

1

我想你可以這樣做。只匹配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 
     . 
)* 
1

嘗試在做一個正則表達式的可讀性:

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

^\*\sheadline - >該項目已知可以像這樣開始。

(?:(?!^\*\sheadline).)* - >匹配任何東西,只要它不包括我們如何知道一個新項目開始。

:END:$ - >它在行尾包含已知的結束語句。

Working demo.