Groovy 1.6.1 Released With New Find and findAll Regexp Methods on String

| Comments

Groovy 1.6.1 was released today, and it includes a patch I submitted a few weeks ago to make working with regular expressions much more groovy. Thanks to everyone that voted for the patch in the Groovy JIRA.

The main functionality is the addition of a variety of find and findAll regular expression aware methods that have been added to string.

If all you need is to scan a string for the portion that matches a regular expression, use find:

assert "32.99" == 'Total Amount: $32.99'.find(/(\d+).(\d{2})/)

If you need to get access to the capture groups of the regular expression, you can specify a closure that any matched item will be passed to. You then have a chance to manipulate the return value:

def roundedAmount(value) {
    value.find(/(\d+).(\d{2})/) { fullMatch, dollars, cents ->       
        return dollars.toInteger() + (cents.toInteger() > 50 ? 1 : 0)

assert "33" == roundedAmount('Total Amount: $32.99')
assert "44" == roundedAmount('I paid $44.28 for it')

If you’re expecting more than one match in a string, you can use the new findAll method to grab the values:

def string = "The stooges are: Moe Fine, Howard Fine, and Larry Fine"
def stooges = string.findAll(/(\w+) Fine/)

assert stooges == ["Moe Fine", "Howard Fine", "Larry Fine"]

Again, if you want to access the capture groups, just add a closure:

def string = "The stooges are: Moe Fine, Howard Fine, and Larry Fine"
def firstNames = string.findAll(/(\w+) Fine/) { match, firstName -> firstName }

assert firstNames == ["Moe", "Howard", "Larry"]

All of the methods are “safe” in that they won’t blow up if a match for the regular expression isn’t found, they’ll just return null. This means that they can also be easily used for groovy truth:

def withDigits = "There are 4 items"

if (withDigits.find(/\d+/)) {
   assert true
} else {
   assert false 

In addition to taking a regular expression string, there is also a variant of each method that takes a precompiled Pattern object. If you are iterating through a ton of strings (such as lines in a file) this version could be useful if you want to avoid recompiling the regex into a pattern every time:

def pattern = ~/.ow/
def owWords = "how now blue cow".findAll(pattern)
assert owWords == ["how", "now", "cow"]

There are additional examples on how to use each of these methods in the groovy documentation for each method:

Thanks to the groovy committers for their suggestions and quick application of the patch (now they just need to apply my other pending patch to remember the font and window size of the groovy console :)