是否需要一种表达正则表达式的更具声明性的方式? :)

时间:2010-08-09 11:21:27

标签: python regex

我正在尝试创建一个Python函数,它可以对正则表达式进行简单的英语描述,并将正则表达式返回给调用者。

目前我正在考虑YAML格式的描述。 因此,我们可以将描述存储为原始字符串变量,将其传递给另一个函数,然后将该函数的输出传递给“re”模块。以下是一个相当简单的例子:

# a(b|c)d+e*
re1 = """
- literal: 'a'
- one_of: 'b,c'
- one_or_more_of: 'd'
- zero_or_more_of: 'e'
"""
myre = re.compile(getRegex(re1))
myre.search(...)

有人认为这种东西会被广泛使用吗? 你知道现有的包可以做到吗? 您对此方法有何限制? 有人认为,在代码中使用声明性字符串会使其更易于维护吗?

4 个答案:

答案 0 :(得分:6)

这实际上与词法分析器/解析器的工作方式非常相似(相同?)。如果你有一个定义的语法,那么你可能写一个解决方案并没有太多麻烦。例如,你可以这样写:

<expression> :: == <rule> | <rule> <expression> | <rule> " followed by " <expression>
<rule>       :: == <val> | <qty> <val>
<qty>        :: == "literal" | "one" | "one of" | "one or more of" | "zero or more of"
<val>        :: == "a" | "b" | "c" | "d" | ... | "Z" | 

这远不是一个完美的描述。有关详细信息,请查看this BNF of the regex language。然后,您可以查看lexingparsing表达式。

如果你这样做,你可能会更接近Natural Language /英文版的正则表达式。


我可以看到这样的工具很有用,但正如之前所说,主要针对初学者。 这种方法的主要限制在于您必须编写的代码量才能将语言转换为正则表达式(和/或反之亦然)。另一方面,我认为双向翻译工具实际上更理想并且看到更多用途。能够使用正则表达式并将其转换为英语可能对发现错误更有帮助。

当然,拾取正则表达式并不需要太长时间,因为语法通常很简洁,并且大多数含义都是非常自我解释的,至少如果你使用|或||在您的语言中为OR,您认为*乘以0-N,+为0-N。

虽然有时我不介意输入“找到一个或多个'a'后跟三位数字或'b'然后'c'”

答案 1 :(得分:6)

请查看pyparsing。您使用RE描述的许多问题与启发我编写该程序包的问题相同。

以下是O'Reilly电子书章节"What's so special about pyparsing?"中pyparsing的一些具体功能。

答案 2 :(得分:2)

可能不完全是你要求的,但是有一种方法可以更可读的方式编写正则表达式(VERBOSE,简称X标志):

rex_name = re.compile("""
    [A-Za-z]    # first letter
    [a-z]+      # the rest
""", re.X)

rex_name.match('Joe')

答案 3 :(得分:2)

对于试图编写易于理解和维护的正则表达式的开发人员,我想知道这种方法是否会提供re.VERBOSE未提供的任何内容。

对于初学者,您的想法可能会有一些吸引力。但是,在沿着这条路走下去之前,您可能会尝试使用捕获组,锚点,先行断言等来模拟更复杂的正则表达式的声明性语法。一个挑战是,您最终可能会使用与正则表达式语言本身一样难以记住的声明性语法。

您也可以考虑表达事物的替代方式。例如,我想到的第一个想法是使用具有简短易记的名称来表达正则表达式。例如:

from refunc import *

pattern = Compile(
    'a',
    Capture(
        Choices('b', 'c'),
        N_of( 'd', 1, Infin() ),
        N_of( 'e', 0, Infin() ),
    ),
    Look_ahead('foo'),
)

但是当我看到它在行动中时,对我来说这看起来很痛苦。正则表达式的许多方面都非常直观 - 例如,+表示“一个或多个”。一种选择是混合方法,允许您的用户将已经简单的正则表达式部分与更深奥的位的函数混合。

pattern = Compile(
    'a',
    Capture(
        '[bc]',
        'd+',
        'e*',
    ),
    Look_ahead('foo'),
)

我想补充一点,根据我的经验,正则表达式是关于学习思考过程。熟悉语法很容易。