How do I do pattern matching using regular expression in Spring EL?

In this Spring Expression Language example we are going to learn how to use regular expression or regex to check if a text matches a certain pattern. Spring EL support regular expression using the matches operator.

The matches operator will check if the value has a pattern defined by the regex string and it returns the evaluation result as a boolean value true if the text matches the regex or false if otherwise.

For example we can use the matches operator to check is a the given email address is a valid email address. As can be seen in the following example:

<property name="emailValid" 
          value="#{user.email matches '^[_A-Za-z0-9-]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$'}"/>

This configuration will evaluate the user.email property to check if the email pattern matches with the given regular expression. If matches then the emailValid property will be set to true otherwise it will be false.

Let’s see the complete example. Here are the spring configuration file, the User bean and a simple class for running the configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="org.kodejava.example.spring.model.User">
        <constructor-arg name="email" value="[email protected]"/>
        <property name="emailValid"
                  value="#{user.email matches '^[_A-Za-z0-9-]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$'}"/>
    </bean>
</beans>

The User bean is a simple pojo with two properties, a string email property and a boolean validEmail property.

package org.kodejava.example.spring.model;

public class User {
    private String email;
    private boolean emailValid;

    public User() {
    }

    public User(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isEmailValid() {
        return emailValid;
    }

    public void setEmailValid(boolean emailValid) {
        this.emailValid = emailValid;
    }
}

And finally the application class.

package org.kodejava.example.spring;

import org.kodejava.example.spring.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpELRegexExample {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spel-regex.xml");

        User user = (User) context.getBean("user");
        System.out.println("user.getEmail()     = " + user.getEmail());
        System.out.println("user.isEmailValid() = " + user.isEmailValid());
    }
}

When we run the code we will obtain the following result:

INFO: Loading XML bean definitions from class path resource [spel-regex.xml]
user.getEmail()     = [email protected]
user.isEmailValid() = true

How do I count the number of capturing groups?

Capturing groups are numbered by counting the opening parentheses from left to right. To find out how many groups are present in the expression, call the groupCount() method on a matcher object. The groupCount() method returns an int showing the number of capturing groups present in the matcher’s pattern.

package org.kodejava.example.util.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CountingGroupDemo {
    public static void main(String[] args) {
        // Define regex to find the word 'quick' or 'lazy' or 'dog'
        String regex = "(quick)|(lazy)|(dog)";
        String text = "the quick brown fox jumps over the lazy dog";

        // Obtain the required matcher
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);

        int groupCount = matcher.groupCount();
        System.out.println("Number of group = " + groupCount);

        // Find every match and print it
        while (matcher.find()) {
            for (int i = 0; i <= groupCount; i++) {
                // Group i substring
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }
    }
}

The result of the program:

Number of group = 3
Group 0: quick
Group 1: quick
Group 2: null
Group 3: null
Group 0: lazy
Group 1: null
Group 2: lazy
Group 3: null
Group 0: dog
Group 1: null
Group 2: null
Group 3: dog

How do I use reluctant quantifier regex?

The reluctant quantifiers start the matcher at the beginning of the input string, then reluctantly eat one character at a time looking for a match. The last thing they try is the entire input string.

package org.kodejava.example.util.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReluctantQuantifierDemo {
    public static void main(String[] args) {
        String[] expressions =
                {"x??", "x*?", "x+?", "x{2}?", "x{2,}?", "x{2,5}?"};
        String input = "xxxxxxx";

        for (String expression : expressions) {
            Pattern pattern = Pattern.compile(expression);
            Matcher matcher = pattern.matcher(input);

            // Find every match and print it
            System.out.println("------------------------------");
            System.out.format("regex:  %s %n", expression);
            while (matcher.find()) {
                System.out.format("Text \"%s\" found at %d to %d%n",
                        matcher.group(), matcher.start(),
                        matcher.end());
            }
        }
    }
}

The results of the snippet shown below:

regex:  x?? 
Text "" found at 0 to 0
Text "" found at 1 to 1
Text "" found at 2 to 2
Text "" found at 3 to 3
Text "" found at 4 to 4
Text "" found at 5 to 5
Text "" found at 6 to 6
Text "" found at 7 to 7
------------------------------
regex:  x*? 
Text "" found at 0 to 0
Text "" found at 1 to 1
Text "" found at 2 to 2
Text "" found at 3 to 3
Text "" found at 4 to 4
Text "" found at 5 to 5
Text "" found at 6 to 6
Text "" found at 7 to 7
------------------------------
regex:  x+? 
Text "x" found at 0 to 1
Text "x" found at 1 to 2
Text "x" found at 2 to 3
Text "x" found at 3 to 4
Text "x" found at 4 to 5
Text "x" found at 5 to 6
Text "x" found at 6 to 7
------------------------------
regex:  x{2}? 
Text "xx" found at 0 to 2
Text "xx" found at 2 to 4
Text "xx" found at 4 to 6
------------------------------
regex:  x{2,}? 
Text "xx" found at 0 to 2
Text "xx" found at 2 to 4
Text "xx" found at 4 to 6
------------------------------
regex:  x{2,5}? 
Text "xx" found at 0 to 2
Text "xx" found at 2 to 4
Text "xx" found at 4 to 6

How do I use quantifier in regex?

A quantifier following a subsequence of a pattern determines the possibilities for how that subsequence of a pattern can repeat. Quantifiers allow you to specify the number of occurrences to match against.

Quantifiers

  • X? : X, once or not at all
  • X* : X, zero or more times
  • X+ : X, one or more times
  • X{n} : X, exactly n times
  • X{n,} : X, at least n times
  • X{n,m} : X, at least n but not more than m times
package org.kodejava.example.util.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexQuantifierDemo {
    public static void main(String[] args) {
        String[] expressions =
                {"x?", "x*", "x+", "x{2}", "x{2,}", "x{2,5}"};

        String input = "xxxxxx yyyxxxxxx zzzxxxxxx";

        for (String expression : expressions) {
            // Compiles the given regular expression into a
            // pattern and creates a matcher that will match
            // the given input against this pattern.
            Pattern pattern = Pattern.compile(expression);
            Matcher matcher = pattern.matcher(input);

            // Find every match and print it
            System.out.println("------------------------------");
            System.out.format("regex:  %s %n", expression);
            while (matcher.find()) {
                System.out.format("Text \"%s\" found at %d to %d%n",
                        matcher.group(), matcher.start(),
                        matcher.end());
            }
        }
    }
}

Here are the result of the program:

------------------------------
regex:  x? 
Text "x" found at 0 to 1
Text "x" found at 1 to 2
Text "x" found at 2 to 3
Text "x" found at 3 to 4
Text "x" found at 4 to 5
Text "x" found at 5 to 6
Text "" found at 6 to 6
Text "" found at 7 to 7
Text "" found at 8 to 8
Text "" found at 9 to 9
Text "x" found at 10 to 11
Text "x" found at 11 to 12
Text "x" found at 12 to 13
Text "x" found at 13 to 14
Text "x" found at 14 to 15
Text "x" found at 15 to 16
Text "" found at 16 to 16
Text "" found at 17 to 17
Text "" found at 18 to 18
Text "" found at 19 to 19
Text "x" found at 20 to 21
Text "x" found at 21 to 22
Text "x" found at 22 to 23
Text "x" found at 23 to 24
Text "x" found at 24 to 25
Text "x" found at 25 to 26
Text "" found at 26 to 26
------------------------------
regex:  x* 
Text "xxxxxx" found at 0 to 6
Text "" found at 6 to 6
Text "" found at 7 to 7
Text "" found at 8 to 8
Text "" found at 9 to 9
Text "xxxxxx" found at 10 to 16
Text "" found at 16 to 16
Text "" found at 17 to 17
Text "" found at 18 to 18
Text "" found at 19 to 19
Text "xxxxxx" found at 20 to 26
Text "" found at 26 to 26
------------------------------
regex:  x+ 
Text "xxxxxx" found at 0 to 6
Text "xxxxxx" found at 10 to 16
Text "xxxxxx" found at 20 to 26
------------------------------
regex:  x{2} 
Text "xx" found at 0 to 2
Text "xx" found at 2 to 4
Text "xx" found at 4 to 6
Text "xx" found at 10 to 12
Text "xx" found at 12 to 14
Text "xx" found at 14 to 16
Text "xx" found at 20 to 22
Text "xx" found at 22 to 24
Text "xx" found at 24 to 26
------------------------------
regex:  x{2,} 
Text "xxxxxx" found at 0 to 6
Text "xxxxxx" found at 10 to 16
Text "xxxxxx" found at 20 to 26
------------------------------
regex:  x{2,5} 
Text "xxxxx" found at 0 to 5
Text "xxxxx" found at 10 to 15
Text "xxxxx" found at 20 to 25

How do I use capturing groups in regex?

Capturing groups are a way to treat multiple characters as a single unit. They are created by placing the characters to be grouped inside a set of parentheses. For example, the regular expression (dog) creates a single group containing the letters d, o and g.

Regular expressions can also define other capturing groups that correspond to parts of the pattern. Each pair of parentheses in a regular expression defines a separate capturing group in addition to the group that the whole expression defines.

package org.kodejava.example.util.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CapturingGroupDemo {
    public static void main(String[] args) {
        // Define regex to find the word 'the' or 'quick'
        String regex = "(the)|(quick)";
        String text = "the quick brown fox jumps over the lazy dog";

        // Compiles the given regular expression into a pattern and
        // Creates a matcher that will match the given input against
        // this pattern.
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);

        // Find every match and print it
        while (matcher.find()) {
            System.out.format("Text \"%s\" found at %d to %d.%n",
                    matcher.group(), matcher.start(), matcher.end());
        }
    }
}

The results of the program are:

Text "the" found at 0 to 3.
Text "quick" found at 4 to 9.
Text "the" found at 31 to 34.