将多个正则表达式组合成一个自动机

时间:2013-03-08 15:47:28

标签: java regex automaton

假设我有一个正则表达式列表(从外部源读取 - 文件,数据库等)。我想检查字符串匹配哪些正则表达式。

我可以通过所有这些正则表达式创建迭代并匹配它们,但列表可能很大,这是一个关键操作。

我可以将所有这些正则表达式合并为一个(在它们之间),但问题是我只能识别第一个匹配的正则表达式,而不是全部。

另一个想法可能是为所有这些正则表达式创建一个自动机,并用相应正则表达式的索引标记最终状态。我正在查看http://cs.au.dk/~amoeller/automaton/,这个库似乎能够使用正则表达式和自动机,但不确定它是否可以扩展以解决我的问题。

你还有其他想法吗?

为了澄清一些评论,我添加了一个代码示例:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class PatternTest {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("(a(?:b|c)a)|((?:a|b)ba)|(ab(?:a|c))");     
        Matcher m = p.matcher("aba");
        System.out.println(m.matches());
        System.out.println(m.groupCount());
        for (int i = 0, n = m.groupCount(); i < n; i++) {
            System.out.println(m.group(i));
        }
    }
}

将打印出来

true
3
aba
aba
null

正如您所看到的那样,只有第一组匹配,而我找不到匹配其他两组的方法。

更多调查结果 - 使用上面的自动机库,问题将减少到以下几点:如果连接两个或多个自动机,如何识别哪个原始自动机对应的最终状态?

3 个答案:

答案 0 :(得分:5)

我实现了基于dk.brics.automaton的解决方案,你可以在这里找到它。 https://github.com/fulmicoton/multiregexp

答案 1 :(得分:3)

对于确定的答案(如果有的话),我们需要更多信息,例如:

  1. 你说正则表达的列表是巨大的;你可以说得更详细点吗?成千上万的?百万?数十亿甚至数十亿?

  2. 谁写了这些正则表达式,他们知道他们在做什么吗?在将正则表达式添加到列表之前是否已经过彻底测试(正确性性能)?

  3. 在示例代码中,您使用matches()方法,该方法需要正则表达式来描述整个字符串。就像正则表达式真的一样 \A(?:(a(?:b|c)a)|((?:a|b)ba)|(ab(?:a|c)))\z
    匹配"aba"但不匹配"aaba""abaa"。如果您在使用Java之前已在其他工具或语言中使用了正则表达式,则此行为可能会让您感到惊讶。传统上,如果正则表达式描述字符串中的任何子串,甚至是零长度子字符串,则字符串总是被称为“匹配”正则表达式。要在Java中获得该行为,您必须使用Matcher的find()方法。

  4. 是否有任何常见因素可以从列表中的所有正则表达式中提取出来,例如最小或最大长度,公共子串或共享字符子集?例如,与您的某个示例模式匹配的任何字符串也必须与[abc]{3}匹配。如果有,你可能想要在严重匹配开始之前运行基于它们的过滤器(可能是正则表达式,也许不是)。 (如果您使用的是Perl,我不会建议这样做,这是一个已经优化过的choc-a-bloc,但是Java并不自豪地接受一点帮助.☺)

  5. 但是我觉得很安全,建议你使用单独的正则表达式,而不是将它们连成一个。 Frankenregex不一定表现更好,故障排除将是一场噩梦!您可以预编译所有Pattern对象,并且可以提前创建Matcher对象并将其重用于所有匹配项,如下所示:

    m.reset(s).usePattern(p);
    

    这是一个demo。我无法做出任何保证(一方面,你仍然受到编写正则表达式的人的支配),但如果解决方案成为可能,我认为这是最有希望的方法。

答案 2 :(得分:2)

dk.brics.automaton并不直接支持这一点,但您可以概括自动机(以及相关的自动机操作)的表示来区分不同类型的接受状态。首先,将一个int字段添加到State类,并在“接受”时使用此字段。已经确定了。