【问题标题】:How to find all possible regex matches in python?如何在python中找到所有可能的正则表达式匹配?
【发布时间】:2014-07-02 11:44:46
【问题描述】:

我正在尝试使用 python 及其正则表达式查找所有可能的单词/标签对或其他嵌套组合。

sent = '(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))'

def checkBinary(sentence):
    n = re.findall("\([A-Za-z-0-9\s\)\(]*\)", sentence)
    print(n)

checkBinary(sent)

Output:
['(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))']

寻找:

['(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))', 
 '(NNP Hoi)', 
 '(NN Hallo)',
 '(NN Hey)', 
 '(NNP (NN Ciao) (NN Adios))',
 '(NN Ciao)',
 '(NN Adios)']

我认为正则表达式也可以找到嵌套的括号单词/标签对,但它不会返回它们。我该怎么做?

【问题讨论】:

    标签: python regex parentheses


    【解决方案1】:

    实际上不可能通过使用正则表达式来做到这一点,因为正则表达式表达了一种由 regular 语法定义的语言,可以通过非有限确定性自动机来解决,其中匹配由状态表示;那么要匹配嵌套括号,您需要能够匹配无限数量的括号,然后拥有一个具有无限数量状态的自动机。

    为了解决这个问题,我们使用了所谓的下推自动机,它用于定义上下文无关语法。

    因此,如果您的正则表达式与嵌套括号不匹配,那是因为它正在表达以下自动机并且与您输入的任何内容都不匹配:

    Play with it

    作为参考,请查看麻省理工学院关于该主题的课程:

    因此,有效解析字符串的一种方法是为嵌套括号构建语法(首先是pip install pyparsing):

    >>> import pyparsing
    >>> strings = pyparsing.Word(pyparsing.alphanums)
    >>> parens  = pyparsing.nestedExpr( '(', ')', content=strings)
    >>> parens.parseString('(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))').asList()
    [['NP', ['NNP', 'Hoi'], ['NN', 'Hallo'], ['NN', 'Hey'], ['NNP', ['NN', 'Ciao'], ['NN', 'Adios']]]]
    

    注意:存在一些使用下推实现嵌套括号匹配的正则表达式引擎。默认的python re 引擎不是其中之一,但存在一个替代引擎,称为regex (pip install regex),它可以进行递归匹配(这使得重新引擎上下文免费),参见this code snippet

    >>> import regex
    >>> res = regex.search(r'(?<rec>\((?:[^()]++|(?&rec))*\))', '(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))')
    >>> res.captures('rec')
    ['(NNP Hoi)', '(NN Hallo)', '(NN Hey)', '(NN Ciao)', '(NN Adios)', '(NNP (NN Ciao) (NN Adios))', '(NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios)))']
    

    【讨论】:

    • CS 的本质。 +1
    • 哦,现代正则表达式could match这种数据。阅读recursive patterns 和/或balancing groupsReference
    • 确实如此,我什至最后建议使用递归模式解决方案。不过,根据定义,这些不再是 regular 表达式了。
    • @FarhadAliNoo 根据形式理论中regular expressions 的定义,正则表达式正在实现正则语法。实现非正则表达式的引擎应该采用不同的名称,例如 nregex(用于 非正则表达式)或 cfexcontext -free 表达式)… 尽管这些功能已经在 regex 引擎中实现,称它们为 regex 就像称 a plane i>“会飞的汽车。所以也许有人应该写一篇关于 HN 的文章来抱怨 :-)
    • 让我们责怪 Perl 人吧! :-D
    【解决方案2】:

    现代语言中使用的正则表达式并不代表正则语言。 zmo 说得对,Language Theroy 中的正则语言由有限状态自动机表示,但使用任何类型回溯的正则表达式,如现代语言中使用的捕获组、环视等,不能由语言中已知的 FSA 表示理论。你如何用 DFA 甚至 NFA 来表示像 (\w+)\1 这样的模式?

    你要找的正则表达式可以是这样的(只匹配两个级别):

    (?=(\((?:[^\)\(]*\([^\)]*\)|[^\)\(])*?\)))
    

    我在 http://regexhero.net/tester/ 上测试过这个

    匹配项在捕获的组中:

    1: (NP (NNP Hoi) (NN Hallo) (NN Hey) (NNP (NN Ciao) (NN Adios))

    1: (NNP Hoi)

    1:(NN你好)

    1:(NN嘿)

    1: (NNP (NN Ciao) (NN Adios))

    1: (NN Ciao)

    1: (NN Adios)

    【讨论】:

    • 我相信@zmo 在结尾NB 部分谈到了现代正则表达式(并举了一个使用递归的例子)。还要小心,您的表达式不会超过两层嵌套:您的第一个匹配项缺少右括号。
    • 哦,你是对的!是的,正则表达式只适用于两层嵌套。
    • 我鼓励大家阅读有关平衡组和递归模式 Hamza 在 zmo 的帖子评论部分中提到的内容。确实是一本非常好的读物。
    • 法哈德,也感谢您的帮助!我认为不适合其他答案,但感谢您的快速回复!
    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多