1. Overview
In this article, we’ll look at the Groovy language features for pattern matching in Strings.
We’ll see how Groovy’s batteries-included approach provides us with a powerful and ergonomic syntax for our basic pattern matching needs.
2. Pattern Operator
The Groovy language introduces the so-called pattern operator ~. This operator can be considered a syntactic sugar shortcut to Java’s java.util.regex.Pattern.compile(string) method.
Let’s check it out in practice as a part of a Spock test:
def "pattern operator example"() {
given: "a pattern"
def p = ~'foo'
expect:
p instanceof Pattern
and: "you can use slashy strings to avoid escaping of blackslash"
def digitPattern = ~/\d*/
digitPattern.matcher('4711').matches()
}
This is also pretty convenient, but we’ll see that this operator is merely the baseline for some other, even more useful operators.
3. Match Operator
Most of the time, and especially when writing tests, we’re not really interested in creating Pattern objects, but instead, want to check if a String matches a certain regular expression (or Pattern). Groovy, therefore, also contains the match operator ==~.
It returns a boolean and performs a strict match against the specified regular expression. Basically, it’s a syntactic shortcut over calling Pattern.matches(regex, string).
Again, we’ll look into it in practice as part of a Spock test:
def "match operator example"() {
expect:
'foobar' ==~ /.*oba.*/
and: "matching is strict"
!('foobar' ==~ /foo/)
}
4. Find Operator
The last Groovy operator in the context of pattern matching is the find operator ~=. In this case, the operator will directly create and return a java.util.regex.Matcher instance.
We can act upon this Matcher instance, of course, by accessing its known Java API methods. But in addition, we’re also able to access matched groups using a multi-dimensional array.
And that’s not all — the Matcher instance will automatically coerce to a boolean type by calling its find() method if used as a predicate. Quoting the official Groovy docs, this means “the =~ operator is consistent with the simple use of Perl’s =~ operator”.
Here, we see the operator in action:
def "find operator example"() {
when: "using the find operator"
def matcher = 'foo and bar, baz and buz' =~ /(\w+) and (\w+)/
then: "will find groups"
matcher.size() == 2
and: "can access groups using array"
matcher[0][0] == 'foo and bar'
matcher[1][2] == 'buz'
and: "you can use it as a predicate"
'foobarbaz' =~ /bar/
}
5. Conclusion
We’ve seen how the Groovy language gives us access to the built-in Java features regarding regular expressions in a very convenient manner.
The official Groovy documentation also contains some concise examples regarding this topic. It’s especially cool if you consider that the code examples in the docs are executed as part of the documentation build.
As always, code examples can be found on GitHub.