我需要在我的Go代码中匹配使用反向引用的正则表达式(例如\ 1)。
这并不容易,因为在Go中,official regexp package使用RE2 engine,chosen to not support backreferences(以及其他一些鲜为人知的功能),以便可以是线性时间执行的保证,因此避免regex denial-of-service attacks。 RE2不支持启用反向引用支持。
在我的代码中,攻击者不存在恶意攻击的风险,我需要反向引用。
我该怎么办?
答案 0 :(得分:8)
在这里回答我自己的问题,我使用golang-pkg-pcre解决了这个问题,它使用libpcre ++,支持反向引用的perl正则表达式。 API为not the same。
答案 1 :(得分:8)
正则表达式非常适合使用常规语法,但如果你的语法不规则(即需要反向引用和类似的东西),你应该切换到更好的工具。有很多很好的工具可用于解析无上下文语法,包括默认情况下随Go分发一起提供的yacc。或者,您也可以编写自己的解析器。 Recursive descent parsers可以很容易地手工编写。
我认为正则表达式在脚本语言(如Perl,Python,Ruby,...)中被过度使用,因为它们的C / ASM驱动的实现通常比那些语言本身更优化,但Go不是这样的语言。正则表达式通常很慢,通常不适合这个问题。
答案 2 :(得分:2)
当我遇到同样的问题时,我使用两步正则表达式匹配解决了它。原始代码是:
if m := match(pkgname, `^(.*)\$\{DISTNAME:S(.)(\\^?)([^:]*)(\\$?)\2([^:]*)\2(g?)\}(.*)$`); m != nil {
before, _, left, from, right, to, mod, after := m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]
// ...
}
代码应该解析${DISTNAME:S|from|to|g}
形式的字符串,它本身是一种使用熟悉的替换语法S|replace|with|
的小模式语言。
两阶段代码如下所示:
if m, before, sep, subst, after := match4(pkgname, `^(.*)\$\{DISTNAME:S(.)([^\\}:]+)\}(.*)$`); m {
qsep := regexp.QuoteMeta(sep)
if m, left, from, right, to, mod := match5(subst, `^(\^?)([^:]*)(\$?)`+qsep+`([^:]*)`+qsep+`(g?)$`); m {
// ...
}
}
match
,match4
和match5
是我自己的regexp
包的包装器,它们会缓存已编译的正则表达式,这样至少编译时间不会浪费了。
答案 3 :(得分:0)
regexp软件包功能FindSubmatchIndex和Expand可以通过反向引用捕获内容。它不是很方便,但仍然可能。 Example