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.
Asked
Active
Viewed 192 times
1

R113
- 11
- 1
-
Would you consider `a+` to match "aa" more than once? – Joni Apr 06 '20 at 15:04
-
You could just use Matcher#find() twice. If the second time fails, then you only have one match. – NomadMaker Apr 06 '20 at 15:08
-
What about [matcher.results().count()](https://stackoverflow.com/a/58946704/9758194)? – JvdV Apr 06 '20 at 15:14
-
@JvdV Didn't know about that, but it is only in Java 9+. – Michael Apr 06 '20 at 15:20
2 Answers
0
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");
}

Tim Biegeleisen
- 502,043
- 27
- 286
- 360
-
Thanks for your answer, would this work on a multiline text ? I'm getting input from a large file and i'm searching amounts, In some case there is exactly one match and my purpose is to determine when. – R113 Apr 06 '20 at 15:09
-
@R113 Yes, just add `(?s)` to the start of the regex pattern using in `String#matches`, and then it should still work in multiline mode. – Tim Biegeleisen Apr 06 '20 at 15:13
0
Just iterate the matches and keep a count.
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("expected one match, found " + 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("[fm]oo").matcher(",foo,moo,");
System.out.println(
getSingleMatch(matcher)
.orElseThrow(() -> new RuntimeException("Expected exactly 1 match"))
//or handle the failure however use you like
);
}
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();
}

Michael
- 41,989
- 11
- 82
- 128