HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Recursive Regular Expressions

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
recursiveregularexpressions

Problem


  • I want to first search for a specific regular expression.



  • If it is not found then I would like to search for another regular expression



  • If that one is also not found then I would like to search for a third



  • (And so on...)



Whenever a matching regular expression is found, I want to return a String array containing:

  • The text before the match



  • The match itself



  • The text after the match



I've only come up with this horribly if-else nesting way of doing it. There's gotta be a better (more extensible and more clean) way but I can't come up with how...

Here is the code, it is currently only containing two regular expressions to search for and it's getting nasty already:

private static String[] findNumbers(String string) {
    Matcher match = Pattern.compile("\\d+[\\:\\.\\,]\\d+").matcher(string);
    if (match.find()) {
        String found = string.substring(match.start(), match.end());
        return new String[]{ string.substring(0, match.start()),
            found, string.substring(match.end()) };
    }
    else {
        match = Pattern.compile("\\d{3,}").matcher(string);
        if (match.find()) {
            String found = string.substring(match.start(), match.end());
            return new String[]{ string.substring(0, match.start()),
                found, string.substring(match.end()) };
        }
        else {
            // Another if-else could be added here
            return new String[]{ string, "", "" };
        }
    }
}

@Test
public void test() {
    assertArrayEquals(new String[]{ "ABC ", "2000", " DEF" }, findNumbers("ABC 2000 DEF"));
    assertArrayEquals(new String[]{ "42 ABC ", "2000", " DEF" }, findNumbers("42 ABC 2000 DEF"));
    assertArrayEquals(new String[]{ "42 ABC ", "18:47", " DEF" }, findNumbers("42 ABC 18:47 DEF"));
}


I want to put priority to one regular expression before trying the next, that's why I have written this code.

Solution

Nesting is not necessary, you can iterate instead...

But first:

  • naming the input String string can be confusing. Of course it's a string, what is it used for though?



  • there is no need to escape the values inside the [...] construct. the pattern: "\\d+[:.,]\\d+" is just fine, and more readable.



  • you should be pre-compiling and then reusing the patterns, instead of re-compiling them every time.



Consider the following:

private static final Pattern[] patternorder = { 
        Pattern.compile("\\d+[:.,]\\d+"),
        Pattern.compile("\\d{3,}")
};

private static String[] findNumbers(String input) {
    for (Pattern pat : patternorder) {
        Matcher match = pat.matcher(input);
        if (match.find()) {
            return new String[] {
                input.substring(0, match.start()),
                input.substring(match.start(), match.end()),
                input.substring(match.end()),
            };
        }
    }
    return new String[]{input, "", ""};
}

Code Snippets

private static final Pattern[] patternorder = { 
        Pattern.compile("\\d+[:.,]\\d+"),
        Pattern.compile("\\d{3,}")
};

private static String[] findNumbers(String input) {
    for (Pattern pat : patternorder) {
        Matcher match = pat.matcher(input);
        if (match.find()) {
            return new String[] {
                input.substring(0, match.start()),
                input.substring(match.start(), match.end()),
                input.substring(match.end()),
            };
        }
    }
    return new String[]{input, "", ""};
}

Context

StackExchange Code Review Q#39020, answer score: 10

Revisions (0)

No revisions yet.