长正则表达式比短正则表达式差吗?
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_with
和 if
s 等编写我们自己的解析操作。但是正则表达式语法是 成熟的 , 强大的 让我们简洁地 表达某些逻辑的系统。
通常正则表达式很难阅读。有 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)
我正在尝试为一个项目学习正则表达式,我想在其中创建一个 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_with
和 if
s 等编写我们自己的解析操作。但是正则表达式语法是 成熟的 , 强大的 让我们简洁地 表达某些逻辑的系统。
通常正则表达式很难阅读。有 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)