首页 > 解决方案 > 正则表达式非贪婪交替

问题描述

我想检查文件的每一行是否与多个正则表达式模式匹配。

示例:测试我的文本文件的这一行

123;456;789

针对 3 种不同的表达方式

1.*;.*;..9
3.*;.*;787
.2.;.*;..9

并在模式匹配或不匹配时做一些事情。所以我需要知道在这个例子中我的所有模式中哪一个匹配或不匹配:只有 P1 和 P3 匹配,所以我在输入上执行动作 1 和动作 3123;456;789

带有嵌套 for 循环的简单解决方案性能不佳(由于算法)。

例子:

for(String row : rows){
   for (Pattern p : patterns){
     if(p.matcher(value).matches()){
       //
     }
   }
}

我正在考虑用“|”内联多个正则表达式 操作员

使用上面的例子:(1.*;.*;..9)|(3.*;.*;787)|(.2.;.*;..9)

String expression = "(1.*;.*;..9)|(3.*;.*;787)|(.2.;.*;..9)";
String value = "123;456;789";
Pattern  pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher(value);

HashMap<Integer,Boolean> results= new HashMap<>();
if(matcher.matches()) {
    int count = matcher.groupCount();
    for (int i = 1; i <= count; ++i) {
        results.put(i, matcher.group(i) != null);
    }
}

但是引擎在第一个匹配的选项处停止

有没有办法在一次调用中测试多种不同的模式?否则我怎样才能改进算法而不是二次的

标签: javaregex

解决方案


这是正则表达式引擎在找到成功匹配时停止的正确行为。要模拟您正在尝试做的事情,您应该使用前瞻,但它们不会中断比赛(很快失败或很快成功)。因此,类似以下正则表达式的内容将尝试匹配三个不同的捕获组。如果捕获组中的一个正则表达式无法匹配,因为它是可选的,则尝试另一个前瞻,这一直持续到结束:

^(?=(1.*;.*;..9$)?)(?=(3.*;.*;787$)?)(?=(.2.;.*;..9$)?)

如果一个组被捕获,您只需要稍后使用捕获组来执行一些代码:

if (capturingGroup == 1) {
    // do something
} else if (capturingGroup == 2) {
...

在此处查看现场演示(在这里您的两个正则表达式匹配且可识别)

注意:您可能希望删除点星以支持更严格的模式。目前它匹配这么多。

注意:由于这里的两个正则表达式不会同时匹配,您可以将上述正则表达式更改为:

^(?:(?=(1.*;.*;..9$)?)(?=(.2.;.*;..9$)?)|(3.*;.*;787)$)

推荐阅读