Java如何检查一个输入与多个正则表达式模式的匹配?

3

如果我走错了方向,请让我知道是否有更好的方法来处理这个问题。

我有一个Java程序,它将有多个模式,我想将其与输入进行比较。如果其中一个模式匹配,则我希望将该值保存在一个字符串中。我可以用单个模式使其工作,但我想能够检查多个模式。

现在我有以下代码来检查输入是否与一个模式匹配:

Pattern pattern = Pattern.compile("TST\\w{1,}");
Matcher match = pattern.matcher(input);
String ID = match.find()?match.group():null;

因此,如果输入是TST1234或abcTST1234,则ID =“TST1234”

我想要多个模式,例如:

Pattern pattern = Pattern.compile("TST\\w{1,}");
Pattern pattern = Pattern.compile("TWT\\w{1,}");
...

然后将其收集起来,再逐一检查与输入进行比对:

List<Pattern> rxs = new ArrayList<Pattern>();
rxs.add(pattern);
rxs.add(pattern2);

String ID = null;

for (Pattern rx : rxs) {
    if (rx.matcher(requestEnt).matches()){
        ID = //???
    }
}

我不确定如何将ID设置为我想要的。我已经尝试过:
ID = rx.matcher(requestEnt).group();

并且

ID = rx.matcher(requestEnt).find()?rx.matcher(requestEnt).group():null;

我不是很确定如何让它工作,也不知道接下来该怎么做。欢迎任何帮助或建议。谢谢。

编辑:是的,模式会随时间变化。因此,模式列表将增长。

我只需要得到匹配的字符串...如果输入是abcTWT123,它将首先与"TST\w{1,}"进行匹配,然后移动到"TWT\w{1,}",由于它与ID字符串匹配,所以ID字符串将设置为"TWT123"。


你想把每个字符串匹配的所有模式都保存到一个映射表中吗?我对你想要的最终输出有点困惑。 - Luke Kot-Zaniewski
根据您的示例,只需将模式更改为Pattern.compile("T[SW]T\\w{1,}"); => 匹配 T 然后是 SW 然后是 T,或者 Pattern.compile("(patternA|otherB)\\w{1,}"); ... 一个好的答案取决于有多少个模式,它们有多不同,有多可配置或动态...编写代码时是否已知所有可能的模式?它们会随时间而改变吗? - Stephen P
是的,模式会随时间变化而改变。只有一个模式最终会匹配(如果有的话),我只需要获取匹配的字符串...例如,如果输入是abcTWT123,它将首先检查是否与“TST \ w {1,}”匹配,然后转到“TWT \ w {1,}”,由于它匹配了ID字符串将被设置为“TWT123”。 - SuperCow
4个回答

4

如果您正在匹配不完整的字符串,则需要在正则表达式中创建一个组以收集结果中的匹配字符串:

List<Pattern> patterns = new ArrayList<>();
patterns.add(Pattern.compile("(TST\\w+)");
...

Optional<String> result = Optional.empty();
for (Pattern pattern: patterns) {
    Matcher matcher = pattern.match();
    if (matcher.matches()) {
        result = Optional.of(matcher.group(1));
        break;
    }
}

或者,如果您熟悉流:

Optional<String> result = patterns.stream()
    .map(Pattern::match).filter(Matcher::matches)
    .map(m -> m.group(1)).findFirst();

另一种选择是使用find(如@Raffaele的答案中所示),它会隐式创建一个组。
您可能想考虑的另一种选择是将所有匹配项放入单个模式中。
Pattern pattern = Pattern.compile("(TST\\w+|TWT\\w+|...");

那么,您可以在一次操作中进行匹配和分组。但是这可能会使随时间变化的匹配更加困难。

第1组是第一个匹配组(即第一组括号内的匹配)。第0组是完整的匹配。因此,如果您想要完整的匹配(从您的问题中我不太确定),那么您可以使用第0组。


我最初认为 OP 也需要一个组,但由于它使用了 match.find() ? match.group(),所以不需要... match.find() 创建了一个隐式组,如果您没有进行任何介入的 find 或 _match_,则 match.group() 将检索到该组。(嗯,这是假设只有一个模式会匹配和/或您在找到匹配项时停止的情况下) - Stephen P
是的,好观点。我没有意识到这就是 OP 的意思。我会编辑我的答案。 - sprinter
Pattern::match方法需要CharSequence作为参数... - L. Monty

4

使用交替符号|(正则表达式的或逻辑):

Pattern pattern = Pattern.compile("TST\\w+|TWT\\w+|etc");

然后只需检查模式一次。

另请注意,{1,} 可以替换为 +


2
也许你只需要在第一个匹配模式时结束循环:
// TST\\w{1,}
// TWT\\w{1,}
private List<Pattern> patterns;

public String findIdOrNull(String input) {
  for (Pattern p : patterns) {
    Matcher m = p.matcher(input);
    // First match. If the whole string must match use .matches()
    if (m.find()) {
      return m.group(0);
    }
  }
  return null; // Or throw an Exception if this should never happen
}

0
如果您的模式都像您的示例TSTTWT一样是简单前缀,那么您可以一次性定义所有这些模式,并使用正则表达式交替符号|,这样您就不需要循环遍历模式。
一个例子:
    String prefixes = "TWT|TST|WHW";
    String regex = "(" + prefixes + ")\\w+";
    Pattern pattern = Pattern.compile(regex);

    String input = "abcTST123";
    Matcher match = pattern.matcher(input);
    String ID = match.find() ? match.group() : null;

    // given this, ID will come out as "TST123"

现在可以从Java的.properties文件或简单文本文件中读取前缀;或将其作为参数传递给执行此操作的方法。
您还可以将前缀定义为逗号分隔列表或文件中每行一个,然后处理它们以将其转换为one|two|three|etc再进行传递。

您可能会循环遍历多个输入,然后只想创建一次regexpattern变量,仅为每个单独的输入创建Matcher。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接