0

I'm trying to create an enum which holds the regex string, while making sure that the pattern only compiles once because pattern compilation is expensive and I do reuse the same pattern a lot. I'm trying to achieve a dynamically compiled Pattern object depending of the type of enum selected. However, I'm stuck at the following. Can anyone kindly provide some guidance, or suggest a better way of achieving this?

public enum LOG_SCANNER{
    FOO_STRING(".*XXXX$"),
    BAR_STRING(".*YYYY.*"),
    ;

    static Pattern p;
    static {
        p = Pattern.compile(regex); // Compilation failes here

    }


    String regex;
    private LOG_NAME_MATCHER(String regex) {
        this.regex = regex;
    }


}

edit: Please note that i'm not using regex to search for something that could be achieved with String.endsWith() or .contains(). ( ".*XXXX$" ) is simply an example.

Community
  • 1
  • 1
Stark
  • 2,581
  • 2
  • 17
  • 20
  • Besides fixing compilation problems, take a look at http://stackoverflow.com/questions/2423376/java-initialization-order-issue-static-vs-instance-fields and related questions. – Oleg Estekhin Feb 06 '15 at 06:36
  • 4
    You are overthinking this. If you use the same pattern many times, put it inside a separate utils / constants class and then use it. – TheLostMind Feb 06 '15 at 06:37
  • 2
    @TheLostMind Actually, it's over-overthinking. Good word! – laune Feb 06 '15 at 06:53
  • @laune - Yep. `static final Pattern pattern = Pattern.compile(...);` would do the trick for him. – TheLostMind Feb 06 '15 at 06:57
  • 1
    @TheLostMind even String.endsWith would do if they are all of the same kind. – laune Feb 06 '15 at 06:59
  • Thanks for your suggestions. Please note that the regex "".*Foo\\.log$" is just an example, i'm not using regex to search for something than can be achieved with .endsWith. – Stark Feb 06 '15 at 07:47
  • Then what about String.contains? - If you are hunting for efficiency the provided examples should stake the field as far as you need to go. Also, you may have thought about some other use where enum might help such as an aggregate containing all patterns. That, too, would have to be considered. – laune Feb 06 '15 at 08:15
  • all built in string functions are not suitable for this particular situation, as the program's purpose is to scan through logs line by line which contains loosely regulated / moderated strings and extracting needed data from it. Yes, I'm trying to use enum to help "organize and aggregate all patterns in one place". It does appear that I might be over-engineering this, but it's alright, just wanted to learn from anyone who is more experienced and perhaps learn a thing or two. – Stark Feb 06 '15 at 11:59
  • This encourages me to add another answer. – laune Feb 06 '15 at 12:04

2 Answers2

2

What about:

public enum LogNameMatcher{
    FOO_LOG(".*Foo\\.log$"),
    BAR_LOG(".*bar\\.log$");

    private final Pattern pattern;

    private LogNameMatcher(final String regex) {
        this.pattern = Pattern.compile(regex);
    }

    public Pattern getPattern() { return this.pattern; }
}

or (as stated in comments)

public final class LogNameMatcher {
    public static final Pattern FOO_LOG = Pattern.compile(".*Foo\\.log$");
    public static final Pattern BAR_LOG = Pattern.compile(".*bar\\.log$");

    private LogNameMatcher() {
        // util class
    }
}
laune
  • 31,114
  • 3
  • 29
  • 42
  • A simple `stringToMatch.endsWith( "Foo.log" )` etc. would be sufficient and much more efficient. – laune Feb 06 '15 at 06:52
0

Following the discussion, an alternative might be to collect the patterns in some Collection:

List<Pattern> patterns = new ArrayList<>();
for( String ps: new String[]{ "...Foo...", "...bar...",... } ){
    patterns.add( Pattern.compile( ps ) );
}

Code using this List of Pattern to establish a match is straightforward, more so than iterating over an EnumSet.

Also, you might do

String[] patstrs = new String[]{ "(.*Foo.*)", "(.*bar.*)", "(.blech.)"};
String ap = String.join( "|", patstrs );
Pattern p = Pattern.compile( ap );
String t = "a Foo is here";
Matcher m = p.matcher( t );
if( m.matches() ){
    for( int i = 1; i <= m.groupCount(); i++ ){
        if( m.group(i) != null ){
            System.out.println( "#" + i + " matches" );
        }
    }
}

This is meant to indicate that you can look for all patterns at the same time while maintaining the patterns as isolated entities. Further processing can be associated with the string index.

laune
  • 31,114
  • 3
  • 29
  • 42