有没有一种方法可以在Java中验证正则表达式仅有一个匹配?

huangapple 未分类评论47阅读模式
英文:

Is there a way to verify a regular expression has exactly one match in Java?

问题

我正在制作一个用于处理发票的正则表达式生成器,我想知道是否有一种方法可以知道我的正则表达式是否与文本的某个部分匹配且仅匹配一次。正则表达式本身并不是非常重要,我只想知道是否可以检查是否只有一个匹配而且没有更多的匹配。
我当然在使用java.util.regex包中的PatternMatcher
我尝试使用matcher.groupCount(),但似乎行不通,因为它涉及的是组的数量而不是匹配的数量。
提前感谢您的回答。

英文:

i'm currently making a regex generator for some invoices, and I wanted to know if there is a way to know that my regular expression matched with one and only one part of the text. The regular expr itself is not really important, I just want to know if I can check there was only one match and no more.
I'm of course using Pattern and Matcher from java.util.regex package.
I tried to use matcher.groupCount() but that doesnt seem to do the trick because it involves group count not the matches count.
Thanks in advance for your answers.

答案1

得分: 0

你可以在这里使用String#matches与一些前瞻逻辑:

String input = "The quick brown fox jumps over the lazy dog.";
if (input.matches("((?!\\bfox\\b).)*\\bfox\\b(?!.*\\bfox\\b).*")) {
    System.out.println("MATCH");
}

上面使用的正则表达式是(String#matches使用隐式的起始/结束锚点):

^((?!\\bfox\\b).)*\\bfox\\b(?!.*\\bfox\\b).*$

这将匹配第一个fox出现,前提是后面的输入字符串中不会再出现fox

编辑:

上述答案可以通过使用(?s)标志启用点号模式来跨行工作:

String input = "The quick brown\nfox jumps \tover the lazy dog.";
if (input.matches("(?s)((?!\\bfox\\b).)*\\bfox\\b(?!.*\\bfox\\b).*")) {
    System.out.println("MATCH");
}
英文:

You could just use String#matches here with some lookahead logic:

String input = "The quick brown fox jumps over the lazy dog.";
if (input.matches("((?!\\bfox\\b).)*\\bfox\\b(?!.*\\bfox\\b).*")) {
    System.out.println("MATCH");
}

The above regex being used is (String#matches uses implicit starting/ending anchors):

^((?!\bfox\b).)*\bfox\b(?!.*\bfox\b).*$

This will match a single first occurrence of fox, provided that fox does not occur anywhere else later in the input string.

Edit:

The above answer can be made to work across lines by enabling dot all mode using the (?s) flag:

String input = "The quick brown\nfox jumps \tover the lazy dog.";
if (input.matches("(?s)((?!\\bfox\\b).)*\\bfox\\b(?!.*\\bfox\\b).*")) {
    System.out.println("MATCH");
}

答案2

得分: 0

只需遍历匹配项并保持计数

    final Matcher matcher = Pattern.compile("[fm]oo").matcher(",foo,moo,");

    int numMatches = 0;
    String match = null;
    while (matcher.find()) {
        numMatches++;
        match = matcher.group();
    }

    if (numMatches > 1) {
        System.out.println("期望找到一个匹配项,实际找到 " + numMatches);
    } else {
        System.out.println(match);
    }

如果您不关心有多少个匹配项您可以在循环中设置条件并且在找到第二个匹配项后使用`break`语句中断循环

或者重构为一个实用方法在这个实现中我假设您不关心有多少个匹配项

    public static void main(String[] args) {
        final Matcher matcher = Pattern.compile("[fm]oo").matcher(",foo,moo,");

        System.out.println(
            getSingleMatch(matcher)
                 .orElseThrow(() -> new RuntimeException("期望找到恰好一个匹配项"))
                 //或者根据需要处理失败
        );
    }
    
    private static Optional<String> getSingleMatch(Matcher matcher) {
        final boolean foundOnce = matcher.find();
        if (!foundOnce) return Optional.empty();
        final String firstMatch = matcher.group();
        final boolean foundTwice = matcher.find();
        return !foundTwice ? Optional.ofNullable(firstMatch) : Optional.empty();
    }
英文:

Just iterate the matches and keep a count.

final Matcher matcher = Pattern.compile(&quot;[fm]oo&quot;).matcher(&quot;,foo,moo,&quot;);

int numMatches = 0;
String match = null;
while (matcher.find()) {
    numMatches++;
    match = matcher.group();
}

if (numMatches &gt; 1) {
    System.out.println(&quot;expected one match, found &quot; + numMatches);
}
else {
    System.out.println(match);
}

If you don't care how many matches there are, you can put a condition in the loop and break as soon as you've found the 2nd one.

Or refactor to a util method. In this implementation, I presumed you didn't care about how many matches there are.

public static void main(String[] args) {
    final Matcher matcher = Pattern.compile(&quot;[fm]oo&quot;).matcher(&quot;,foo,moo,&quot;);

    System.out.println(
        getSingleMatch(matcher)
             .orElseThrow(() -&gt; new RuntimeException(&quot;Expected exactly 1 match&quot;))
             //or handle the failure however use you like
    );
}

private static Optional&lt;String&gt; getSingleMatch(Matcher matcher) {
    final boolean foundOnce = matcher.find();
    if (!foundOnce) return Optional.empty();
    final String firstMatch = matcher.group();
    final boolean foundTwice = matcher.find();
    return !foundTwice ? Optional.ofNullable(firstMatch) : Optional.empty();
}

huangapple
  • 本文由 发表于 2020年4月6日 22:54:09
  • 转载请务必保留本文链接:https://java.coder-hub.com/61062604.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定