【问题标题】:Python regex - get items from orgmode filesPython regex - 从 orgmode 文件中获取项目
【发布时间】:2017-03-01 21:06:44
【问题描述】:

我有以下组织模式语法:

** Hardware [0/1]
 - [ ] adapt a programmable motor to a tripod to be used for panning 
** Reading - Technology [1/6]
 - [X] Introduction to Networking - Charles Severance
 - [ ] A Tour of C++ - Bjarne Stroustrup
 - [ ] C++ How to Program - Paul Deitel
 - [X] Computer Systems - Randal Bryant
 - [ ] The C programming language - Brian Kernighan
 - [ ] Beginning Linux Programming -Matthew and Stones
** Reading - Health [3/4]
 - [ ] Patrick McKeown - The Oxygen Advantage
 - [X] Total Knee Health - Martin Koban
 - [X] Supple Leopard - Kelly Starrett
 - [X] Convict Conditioning 1 and 2  

而我要提取的项目,比如:

 getitems "Hardware"

我应该得到:

  - [ ] adapt a programmable motor to a tripod to be used for panning  

如果我要求“阅读 - 健康”,我应该得到:

 - [ ] Patrick McKeown - The Oxygen Advantage
 - [X] Total Knee Health - Martin Koban
 - [X] Supple Leopard - Kelly Starrett
 - [X] Convict Conditioning 1 and 2 

我正在使用以下模式:

   pattern = re.compile("\*\* "+ head + " (.+?)\*?$", re.DOTALL)

询问“阅读 - 技术”时的输出是:

  - [X] Introduction to Networking - Charles Severance
  - [ ] A Tour of C++ - Bjarne Stroustrup
  - [ ] C++ How to Program - Paul Deitel
  - [X] Computer Systems - Randal Bryant
  - [ ] The C programming language - Brian Kernighan
  - [ ] Beginning Linux Programming -Matthew and Stones
   ** Reading - Health [3/4]
  - [ ] Patrick McKeown - The Oxygen Advantage
  - [X] Total Knee Health - Martin Koban
  - [X] Supple Leopard - Kelly Starrett
  - [X] Convict Conditioning 1 and 2  

我也试过了:

   pattern = re.compile("\*\* "+ head + " (.+?)[\*|\z]", re.DOTALL)

最后一个对除最后一个以外的所有标题都适用。

询问“阅读 - 健康”时的输出:

 - [ ] Patrick McKeown - The Oxygen Advantage
 - [X] Total Knee Health - Martin Koban
 - [X] Supple Leopard - Kelly Starrett

如您所见,它与最后一行不匹配。

我使用的是 python 2.7 和 findall。

【问题讨论】:

  • \*\* Reading - Health (.*?)(?:\*\*|$)

标签: python regex org-mode


【解决方案1】:

你可以通过

import re

string = """
** Hardware [0/1]
 - [ ] adapt a programmable motor to a tripod to be used for panning 
** Reading - Technology [1/6]
 - [X] Introduction to Networking - Charles Severance
 - [ ] A Tour of C++ - Bjarne Stroustrup
 - [ ] C++ How to Program - Paul Deitel
 - [X] Computer Systems - Randal Bryant
 - [ ] The C programming language - Brian Kernighan
 - [ ] Beginning Linux Programming -Matthew and Stones
** Reading - Health [3/4]
 - [ ] Patrick McKeown - The Oxygen Advantage
 - [X] Total Knee Health - Martin Koban
 - [X] Supple Leopard - Kelly Starrett
 - [X] Convict Conditioning 1 and 2  
 """

def getitems(section):
    rx = re.compile(r'^\*{2} ' + re.escape(section) + r'.+[\n\r](?P<block>(?:(?!^\*{2})[\s\S])+)', re.MULTILINE)
    try:
        items = rx.search(string)
        return items.group('block')
    except:
        return None

items = getitems('Reading - Technology')
print(items)

working on ideone.com


代码的核心是(浓缩的)表达式:
^\*{2}.+[\n\r]       # match the beginning of the line, followed by two stars, anything else in between and a newline
(?P<block>           # open group "block"
    (?:              # non-capturing group
        (?!^\*{2})   # a neg. lookahead, making sure no ** follows at the beginning of a line
        [\s\S]       # any character...
    )+               # ...at least once
)                    # close group "block"

您的搜索字符串插入到实际代码中** 之后的位置。在 regex101.com 上查看 Reading - Technology 的演示。


作为后续,您也可以只返回 选定的值,如下所示:
def getitems(section, selected=None):
    rx = re.compile(r'^\*{2} ' + re.escape(section) + r'.+[\n\r](?P<block>(?:(?!^\*{2})[\s\S])+)', re.MULTILINE)
    try:
        items = rx.search(string).group('block')
        if selected:
            rxi = re.compile(r'^ - \[X\]\ (.+)', re.MULTILINE)
            try:
                selected_items = rxi.findall(items)
                return selected_items
            except:
                return None
         return items
    except:
        return None

items = getitems('Reading - Health', selected=True)
print(items)

【讨论】:

  • 谢谢,它改进了整体代码......而且 regex101.com 是一个很棒的网站
  • @daleonpz:添加了仅返回选定值的版本。​​
【解决方案2】:

如果您确定您的物品中没有字符 *,您可以使用:

re.compile(r"\*\* "+head+r" \[\d+/\d+\]\n([^*]+)\*?")

【讨论】:

    【解决方案3】:

    不确定整个比赛是否需要正则表达式。我只需使用正则表达式来匹配** 行,然后返回行,直到您看到下一个** 行。

    类似

    pattern = re.compile("\*\* "+ head)
    
    start = False
    output = []
    for line in my_file:
        if pattern.match(line):
             start = True
             continue
        elif line.startswith("**"): # but doesn't match pattern
            break
    
        if start:
            output.append(line)
    
    # now `output` should have the lines you want
    

    【讨论】:

    • 正则表达式非常适合匹配结构化数据,例如始终具有特定格式的行。当您必须在您关心的行之间匹配一堆随机文本时,使用起来会变得更加棘手,这就是为什么我通常会避免您尝试使用的方法。
    • 再看一眼,我的回答中的pattern.match 也可能是line.startswith("** " + head)
    猜你喜欢
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多