长正则表达式比短正则表达式差吗?

Are long regular expressions worse than short ones?

我正在尝试为一个项目学习正则表达式,我想在其中创建一个 textmate grammar,正则表达式看起来相对简单但对我来说真的很难阅读,所以我尝试创建一个实用模块帽子可以生成它们,它有点像预期的那样工作,并生成实际工作的正则表达式,所有别名都使用易于理解的名称。

例如:

struc_enum = OrGroup("struct", "enum")
whitespace = TAB_SPACE.at_least(1)

结果:

(?:struct|enum)
[ \t]+

在这种情况下,使用 python 别名没有太大好处,但我可以这样做:

valid_name = r"\b" + Group(ALPHA, ALPHANUMERIC.repeated())
struc_enum = OrGroup("struct", "enum")
typed_name = (struc_enum + whitespace).optional() + valid_name + whitespace + valid_name.captured()

这就是 print(typed_name) 显示的内容:

(?:(?:(?:struct|enum)[ \t]+)?\b[a-zA-Z][a-zA-Z\d]*[ \t]+(\b[a-zA-Z][a-zA-Z\d]*))

此方法可用于创建小片段并将它们连接起来以构建更复杂的模式,但对于每个连接级别,表达式都会呈指数级增长,这样我就可以很容易地得到:

(?:(func)[\s]+([a-zA-Z_]+[a-zA-Z\d_]*)[\s]*\([\s]*(?:[a-zA-Z_]+[a-zA-Z\d_]*(?:[\s]*[a-zA-Z_]+[a-zA-Z\d_]*[*]{,2})?(?:[\s]*,[\s]*[a-zA-Z_]+[a-zA-Z\d_]*(?:[\s]*[a-zA-Z_]+[a-zA-Z\d_]*[*]{,2})?)*[\s]*)?\))

在原子语法中,上面这个大正则表达式可以匹配这样的行,但它似乎在其他地方不起作用:

func myfunc(asd asd*, asd*, asdasd)
func do_foo01(type arg1, int arg2)

如果有足够的耐心,人类可能会构建一个等效的表达式,但可能要短得多,这就提出了问题。就计算开销而言,大正则表达式是否比等效的较短正则表达式更差或更好?在什么时候我们可以认为正则表达式太大了?

我认为这是个好主意,但您需要清楚自己所从事项目的规模。

我们几乎从不需要使用正则表达式;我们可以拆开每个字符串并使用 starts_withifs 等编写我们自己的解析操作。但是正则表达式语法是 成熟的 强大的 让我们简洁地 表达某些逻辑的系统。

通常正则表达式很难阅读。有 some tools 可以提供帮助,但是 不太简洁 系统来完成我们目前使用正则表达式所做的事情的想法是合理的。困难的部分将是复制现有正则表达式系统的广度能力可靠性

我猜你最好学会忍受正则表达式的密度。也许 我们 为 sting-parsing 构建一个更易于阅读的系统可能会更好,但你将有大约 20 年的时间来赶上进度。

关于性能: 正则表达式是(可以)编译的。根据上下文,这可以带来很大的性能优势。
无论如何,就像任何足够强大的语言一样,指令的长度并不能很好地表明它的 运行 时间复杂度。

由于您最初要解决的问题是长正则表达式难以阅读,您不妨考虑扩展(冗长)的正则表达式。扩展的正则表达式允许空格和注释,这可以使正则表达式更易于阅读。

对比这个正则表达式:

charref = re.compile("&#(0[0-7]+"
                     "|[0-9]+"
                     "|x[0-9a-fA-F]+);")

使用相同的正则表达式,注释:

charref = re.compile(r"""
 &[#]                # Start of a numeric entity reference
 (
     0[0-7]+         # Octal form
   | [0-9]+          # Decimal form
   | x[0-9a-fA-F]+   # Hexadecimal form
 )
 ;                   # Trailing semicolon
""", re.VERBOSE)

示例取自 Regular Expression HOWTO