如何在Go中匹配正则表达式和反向引用?

时间:2014-05-31 10:33:44

标签: regex go backreference

我需要在我的Go代码中匹配使用反向引用的正则表达式(例如\ 1)。

这并不容易,因为在Go中,official regexp package使用RE2 enginechosen to not support backreferences(以及其他一些鲜为人知的功能),以便可以是线性时间执行的保证,因此避免regex denial-of-service attacks。 RE2不支持启用反向引用支持。

在我的代码中,攻击者不存在恶意攻击的风险,我需要反向引用。

我该怎么办?

4 个答案:

答案 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 {
        // ...
    }
}

matchmatch4match5是我自己的regexp包的包装器,它们会缓存已编译的正则表达式,这样至少编译时间不会浪费了。

答案 3 :(得分:0)

regexp软件包功能FindSubmatchIndexExpand可以通过反向引用捕获内容。它不是很方便,但仍然可能。 Example