SuperCow
SuperCow

Reputation: 1613

Java how to check multiple regex patterns against an input?

(If I'm taking the complete wrong direction let me know if there is a better way I should be approaching this)

I have a Java program that will have multiple patterns that I want to compare against an input. If one of the patterns matches then I want to save that value in a String. I can get it to work with a single pattern but I'd like to be able to check against many.

Right now I have this to check if an input matches one pattern:

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

So, if the input was TST1234 or abcTST1234 then ID = "TST1234"

I want to have multiple patterns like:

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

and then to a collection and then check each one against the input:

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 = //???
    }
}

I'm not sure how to set ID to what I want. I've tried

ID = rx.matcher(requestEnt).group();

and

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

Not really sure how to make this work or where to go from here though. Any help or suggestions are appreciated. Thanks.

EDIT: Yes the patterns will change over time. So The patten list will grow.

I just need to get the string of the match...ie if the input is abcTWT123 it will first check against "TST\w{1,}", then move on to "TWT\w{1,}" and since that matches the ID String will be set to "TWT123".

Upvotes: 3

Views: 21271

Answers (4)

Stephen P
Stephen P

Reputation: 14810

If your patterns are all going to be simple prefixes like your examples TST and TWT you can define all of those at once, and user regex alternation | so you won't need to loop over the patterns.

An example:

    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"

Now prefixes could be read in from a java .properties file, or a simple text file; or passed as a parameter to the method that does this.
You could also define the prefixes as a comma-separated list or one-per-line in a file then process that to turn them into one|two|three|etc before passing it on.

You may be looping over several inputs, and then you would want to create the regex and pattern variables only once, creating only the Matcher for each separate input.

Upvotes: 0

Bohemian
Bohemian

Reputation: 425198

Use an alternation | (a regex OR):

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

Then just check the pattern once.

Note also that {1,} can be replaced with +.

Upvotes: 4

sprinter
sprinter

Reputation: 27976

To collect the matched string in the result you may need to create a group in your regexp if you are matching less than the entire string:

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;
    }
}

Or, if you are familiar with streams:

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

The alternative is to use find (as in @Raffaele's answer) that implicitly creates a group.

Another alternative you may want to consider is to put all your matches into a single pattern.

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

Then you can match and group in a single operation. However this might might it harder to change the matches over time.

Group 1 is the first matched group (i.e. the match inside the first set of parentheses). Group 0 is the entire match. So if you want the entire match (I wasn't sure from your question) then you could perhaps use group 0.

Upvotes: 4

Raffaele
Raffaele

Reputation: 20885

Maybe you just need to end the loop when the first pattern matches:

// 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
}

Upvotes: 2

Related Questions