3

(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".

3
  • do you want to save all the patterns that match per string to a map? I'm a little confused by your desired end output Commented Mar 23, 2017 at 22:54
  • Given your example it could be as simple as changing your pattern to Pattern.compile("T[SW]T\\w{1,}"); => match T then S-or-W then T, or Pattern.compile("(patternA|otherB)\\w{1,}"); ... a good answer depends on how many patterns, how different they are, how configurable or dynamic... are all possible patterns known when you write the code? Will they change over time? Commented Mar 23, 2017 at 22:56
  • Yes the patterns will change over time. Only one of the patterns will end up matching (if any), 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". Commented Mar 23, 2017 at 23:00

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I was first thinking OP needed a group too, but since it's using match.find() ? match.group() it doesn't... match.find() creates an implicit group which match.group() retrieves if you don't do any intervening find or match. (well, that's assuming only one of the patterns will match and/or you stop when you find a match)
Yep good point. I hadn't realised that's what OP meant. I'll edit my answer.
The Pattern::match - method requires the CharSequence as parameter...
4

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 +.

Comments

2

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
}

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.