Groovy 1.6.1 released with new find and findAll regexp methods on String

2009/04/7

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 :)

There are 4 comments in this article:

  1. 2009/04/8Ted Naleid » Groovy: Don’t Fear the RegExp say:

    [...] if you’re using Groovy 1.6.1 or greater (released April 2009), check out the new find and find all methods in this post. Some people, when confronted with a problem, think “I know, I’ll use regular [...]

  2. 2009/04/8Guillaume Laforge say:

    Thank you for this contribution, much appreciated ;-)

  3. 2009/04/20Kelly Robinson say:

    Thanks very much for this Ted.

  4. 2009/04/22Michel say:

    Nice explanation, I was missing this on the Groovy site ;-)
    Shouldn’t be this included on de Groovy Wiki???

Write a comment: