Table of Contents
-
Strings
- Turn Methods into Closures
- New Dollar Slashy Strings
- Get to Know More About a GString
- Check if String is a Number
- What Character Are You?
- Access Strings with Subscript Operator
- Capitalize Strings
- Uncapitalize Strings
- Base64 Encoding
- Check if a String Only Contains Whitespaces
- Convert String to Boolean
- Padding Strings
- Working with Lines in Strings
- Getting Parts Of A String Enclosed By Strings
- Using the replaceAll Methods from String
- Replace Characters in a String with CollectReplacements
- Text Translation
- Remove Parts of a String
- Remove Part of String With Regular Expression Pattern
- Taking Or Dropping Number Of Characters From A String
- Splitting Strings
- Get Unique Characters in a String
- Partial Matches
- Transform String into Enum
- String Continuation
- Strip Leading Spaces from Lines
- Strip Leading Spaces from Lines with Margin
- Formatted Strings with sprintf
- Expand or Unexpand Space or Tab Delimited Text
- Normalize and Denormalize Linefeeds and Carriage Returns
- Base64 URL and Filename Safe Encoding
- Calculate MD5 And SHA Hash Values
- Converting Byte Array to Hex String
- GString as Writable
- Closure as Writable
-
Maps
- Check if Maps are Equal
- Sorting a Map
- Turn a List into a Map
- Complex Keys in Maps
- Use inject Method on a Map
- Intersect Maps
- Subtracting Map Entries
- Process Map Entries in Reverse
- Getting a Submap from a Map
- Grouping Map Elements
- Get Value from Map or a Default Value
- Map with Default Values
- Determine Min and Max Entries in a Map
- Represent Map As String
- Turn A Map Or List As String To Map Or List
Strings
Turn Methods into Closures
Groovy supports closures and they are very useful when we create Groovy applications. For example we can pass closures as arguments to methods to execute them. We can create closures ourselves, but we can also convert a method to a closure with the .&
operator. And we can use the converted method just like a normal closure. Because Groovy can use Java objects we can also convert a Java method into a closure.
Let's start with a simple Java class:
public class JavaObject {
public static void javaSays(final String s) {
System.out.println("Java says: Hello " + s + "!");
}
}
With the following script we use this Java class and convert the javaSays
method to a closure:
// Simple list with names.
def names = ['groovy', 'grails', 'mrhaki']
// Simple closure.
names.each { println 'Normal closure says: Hello ' + it + '!' }
// Groovy method to convert to closure.
def groovySays(s) {
"Groovy says: Hello ${s}!"
}
// Use .& syntax to convert method to closure.
names.each(this.&groovySays)
// Convert Java method to closure and use it.
def javaSays = JavaObject.&javaSays
names.each javaSays
If we run this script we get the following output:
Normal closure says: Hello groovy!
Normal closure says: Hello grails!
Normal closure says: Hello mrhaki!
Groovy says: Hello groovy!
Groovy says: Hello grails!
Groovy says: Hello mrhaki!
Java says: Hello groovy!
Java says: Hello grails!
Java says: Hello mrhaki!
Original post written on August 19, 2009
New Dollar Slashy Strings
Groovy already has a lot of ways to define a String value, and with Groovy 1.8 we have another one: the dollar slashy String. This is closely related to the slashy String definition we already knew (which also can be multi-line by the way, added in Groovy 1.8), but with different escaping rules. We don't have to escape a slash if we use the dollar slashy String format, which we would have to do otherwise.
def source = 'Read more about "Groovy" at http://mrhaki.blogspot.com/'
// 'Normal' slashy String, we need to escape / with \/
def regexp = /.*"(.*)".*\/(.*)\//
def matcher = source =~ regexp
assert matcher[0][1] == 'Groovy'
assert matcher[0][2] == 'mrhaki.blogspot.com'
// Dollar slash String.
def regexpDollar = $/.*"(.*)".*/(.*)//$
def matcherDollar = source =~ regexpDollar
assert matcherDollar[0][1] == 'Groovy'
assert matcherDollar[0][2] == 'mrhaki.blogspot.com'
def multiline = $/
Also multilines
are supported.
/$
Original post written on April 27, 2011
Get to Know More About a GString
One of Groovy's great features is the GString. With the GString we can write strings containing expressions that are evaluated. We create a GString if our string is inside double quotes. We can found out information about the expressions in our GString with some simple methods and properties:
def user = 'mrhaki'
def language = 'Groovy'
def s = "Hello ${user}, welcome to ${language}."
assert 2 == s.valueCount
assert ['mrhaki', 'Groovy'] == s.values
assert 'mrhaki' == s.getValue(0)
assert 'Groovy' == s.getValue(1)
assert 32 == s.length()
assert 'Hello ' == s.strings[0]
assert ', welcome to ' == s.strings[1]
assert '.' == s.strings[2]
assert 'Hello mrhaki, welcome to Groovy.' == s
Original post written on July 14, 2010
Check if String is a Number
Groovy adds several methods to the String
class to see if the string value is a number. We can check for all kind of number type like Integer
, Double
, BigDecimal
and more.
assert '42'.isNumber()
assert '42'.isInteger() && '42'.isLong() && '42'.isBigInteger()
assert '42.42'.isDouble() && /42.42/.isBigDecimal() && '42.42'.isFloat()
Original post written on January 3, 2010
What Character Are You?
Groovy adds a couple of methods to the Character
class to determine of the character is a letter, digit, whitespace, upper- or lowercase.
def str = 'a1cB \n.9'
def characters = str.chars // Convert to char[]
assert characters[0].isLetter() // 'a'
assert characters[1].isDigit() // '1'
assert characters[2].isLowerCase() // 'c'
assert characters[3].isUpperCase() // 'B'
assert characters[4].isWhitespace() // ' '
assert characters[5].isWhitespace() // '\n'
assert !characters[6].isLetterOrDigit() // '.'
assert characters[7].isLetterOrDigit() // '9'
Original post written on December 29, 2009
Access Strings with Subscript Operator
Groovy adds a lot of support to the String
class. The getAt
method is added and that means we can use the subscript operator ([]
) to access parts of a String.
def s = 'Accessing Strings in Groovy is easy.'
assert 'A' == s[0]
assert 'A' == s.getAt(0)
assert 'Groovy' == s[21..26] // We can use ranges.
assert 'easy.' == s[s.indexOf('ea')..-1]
// We can also use each method on a String.
s[21..26].each { println "$it-" } // Output: G-r-o-o-v-y-
Original post written on October 31, 2009
Capitalize Strings
Groovy 1.7.3 adds the capitalize()
method to the String
class. This will capitalize the first letter of the String:
assert 'MrHaki' == 'mrHaki'.capitalize()
assert 'Groovy' == 'groovy'.capitalize()
assert 'Groovy is Gr8!' == 'groovy is Gr8!'.capitalize()
Original post written on June 14, 2010
Uncapitalize Strings
Since Groovy 2.4.8 we can use the uncapitalize
method on CharSequence
objects. The capitalize
method was already available for a long time, but now we have the opposite as well.
In the following example we see that the uncapitalize
method only replaces the first letter of a String
value to lower case:
assert 'Groovy'.uncapitalize() == 'groovy'
assert 'MrHaki'.uncapitalize() == 'mrHaki'
String message = 'Groovy Rocks!'
assert message.uncapitalize() == 'groovy Rocks!'
Written with Groovy 2.4.8.
Original post written on January 16, 2017
Base64 Encoding
The byte[]
and String
classes in Groovy's GDK have methods to Base64 encode and decode Strings.
def s = 'Argh, Groovy you say, mate?'
String encoded = s.bytes.encodeBase64().toString()
assert 'QXJnaCwgR3Jvb3Z5IHlvdSBzYXksIG1hdGU/' == encoded
byte[] decoded = encoded.decodeBase64()
assert s == new String(decoded)
Run this script on Groovy web console.
Original post written on November 4, 2009
Check if a String Only Contains Whitespaces
In Groovy we can check if a String
value only contains whitespaces with the isAllWhitespace()
method. The method checks for spaces, but also takes into account tab and newline characters as whitespace.
assert ''.allWhitespace
assert ' '.allWhitespace
assert '\t '.allWhitespace
assert ' \r\n '.allWhitespace
assert !'mrhaki'.allWhitespace
Original post written on September 9, 2013
Convert String to Boolean
Groovy adds the toBoolean()
method to the String
class. If the value of the string is true, 1 or y the result is true, otherwise it is false.
assert "y".toBoolean()
assert 'TRUE'.toBoolean()
assert ' trUe '.toBoolean()
assert " y".toBoolean()
assert "1".toBoolean()
assert ! 'other'.toBoolean()
assert ! '0'.toBoolean()
assert ! 'no'.toBoolean()
assert ! ' FalSe'.toBoolean()
Original post written on November 13, 2009
Padding Strings
Groovy extends the String
class with a couple of padding methods. These methods allows us to define a fixed width a String
value must occupy. If the String
itself is less than the fixed width then the space is padded with spaces or any other character or String
we define. We can pad to the left or the right of the String
or both left and right and put the String
in the center.
These methods are especially useful when we create Groovy scripts that run on the console and we want to format some output.
assert ' Groovy ' == 'Groovy'.center(12)
assert 'Groovy ' == "Groovy".padRight(12)
assert ' Groovy' == /Groovy/.padLeft(12)
assert '---Groovy---' == "Groovy".center(12, '-')
assert 'Groovy * * *' == "Groovy".padRight(12, ' *')
assert 'Groovy Groovy Groovy' == 'Groovy'.padLeft(20, 'Groovy ')
def createOutput = {
def table = [
// Page, Response time, Size
['page1.html', 200, 1201],
['page2.html', 42, 8853],
['page3.html', 98, 3432],
['page4.html', 432, 9081]
]
def total = { data, index ->
data.inject(0) { result, row -> result += row[index] }
}
def totalTime = total.curry(table, 1)
def totalSize = total.curry(table, 2)
def out = new StringBuffer()
out << ' Summary '.center(15, "*") << '\n\n'
out << 'Total pages:'.padRight(25)
out << table.size().toString().padLeft(6) << '\n'
out << 'Total response time (ms):'.padRight(25)
out << totalTime().toString().padLeft(6) << '\n'
out << 'Total size (KB):'.padRight(25)
out << totalSize().toString().padLeft(6) << '\n\n'
out << ' Details '.center(15, "*") << '\n\n'
table.each {
out << it[0].padRight(14)
out << it[1].toString().padLeft(5)
out << it[2].toString().padLeft(8)
out << '\n'
}
out.toString()
}
assert '''\
*** Summary ***
Total pages: 4
Total response time (ms): 772
Total size (KB): 22567
*** Details ***
page1.html 200 1201
page2.html 42 8853
page3.html 98 3432
page4.html 432 9081
''' == createOutput()
Original post written on September 20, 2009
Working with Lines in Strings
In Groovy we can create multiline strings, which contain line separators. But we can also read text from an file containing line separators. The Groovy String GDK contains method to work with strings that contain line separators. We can loop through the string line by line, or we can do split on each line. We can even convert the line separators to the platform specific line separators with the denormalize()
method or linefeeds with the normalize()
method.
def multiline = '''\
Groovy is closely related to Java,
so it is quite easy to make a transition.
'''
// eachLine takes a closure with one argument, that
// contains the complete line.
multiline.eachLine {
if (it =~ /Groovy/) {
println it // Output: Groovy is closely related to Java,
}
}
// or eachLine has a closure with two argument, the current line
// and the line count.
multiline.eachLine { line, count ->
if (count == 0) {
println "line $count: $line" // Output: line 0: Groovy is closely related to Java,
}
}
def platformLinefeeds = multiline.denormalize()
def linefeeds = multiline.normalize()
// Read all lines and convert to list.
def list = multiline.readLines()
assert list instanceof ArrayList
assert 2 == list.size()
assert 'Groovy is closely related to Java,' == list[0]
def records = """\
mrhaki\tGroovy
hubert\tJava
"""
// splitEachLine will split each line with the specified
// separator. The closure has one argument, the list of
// elements separated by the separator.
records.splitEachLine('\t') { items ->
println items[0] + " likes " + items[1]
}
// Output:
// mrhaki likes Groovy
// hubert likes Java
Run this script in Groovy web console.
Original post written on November 1, 2009
Getting Parts Of A String Enclosed By Strings
Groovy 3 adds the takeBetween
method to the String
class. With this method we can get all the characters that are enclosed by string values. We can specify one enclosed string value and then all text between the the first occurrence of the string and the second occurrence is returned. If multiple parts are enclosed by the string values we can also specify which occurrence we want. If the text is enclosed by different string values we can use a variant of takeBetween
that takes two string values to indicate the boundaries of the text we want. Also with two different enclosed string values we can use an argument to get the n-th occurrence of the string that is found.\
Since Groovy 3 we can also use takeBefore
and takeAfter
to get the string before or after a given string value. All three methods will return an empty string if no text can be found.
In the following example we use the takeBefore
, takeAfter
and takeBetween
methods with different arguments:
def text = 'Just saying: "Groovy is gr8!"'
// Return all characters before the first quote.
assert text.takeBefore('"') == 'Just saying: '
// Return everything after the colon.
assert text.takeAfter(': ') == '"Groovy is gr8!"'
// Return everything between two quotes.
assert text.takeBetween('"') == 'Groovy is gr8!'
// Return text between is and !.
assert text.takeBetween('is', '!') == ' gr8'
// When no value can be found
// an empty string is returned.
assert text.takeBefore('?') == ''
assert text.takeAfter('Java') == ''
assert text.takeBetween('-') == ''
assert text.takeBetween('[', '/') == ''
def sample = 'JVM languages are "Groovy", "Clojure", "Java".'
assert sample.takeBetween('"') == 'Groovy'
// We can also specify which occurrence we
// want for a text between same strings.
assert sample.takeBetween('"', 0) == 'Groovy'
assert sample.takeBetween('"', 1) == 'Clojure'
assert sample.takeBetween('"', 2) == 'Java'
def users = "Users: [mrhaki], [hubert]"
assert users.takeBetween('[', ']') == 'mrhaki'
// We can also specify which occurrence we
// want for a text between to strings.
assert users.takeBetween('[', ']', 0) == 'mrhaki'
assert users.takeBetween('[', ']', 1) == 'hubert'
// When no occurrence an empty string is returned.
assert users.takeBetween('[', ']', 2) == ''
Written with Groovy 3.0.2.
Original post written on March 11, 2020
Using the replaceAll Methods from String
Groovy adds two extra replaceAll
methods to the String
class. First we can pass a Pattern
instead of a String
argument with replaceAll(Pattern, String)
. And with the other method we can use a closure to replace a value found with replaceAll(String, Closure)
.
def s = "Programming with Groovy is fun!"
assert "Programming with Groovy rocks!" == s.replaceAll(~/is fun!/, "rocks!") // Groovy extension to \
String.
assert "Programming with Groovy is awesome." == s.replaceAll("fun!", "awesome.") // java.lang.String.\
replaceAll.
// Replace found String with result of closure.
def replaced = s.replaceAll(/fun/) {
def list = ['awesome', 'cool', 'okay']
list[new Random().nextInt(list.size())]
}
assert [
"Programming with Groovy is awesome!",
"Programming with Groovy is cool!",
"Programming with Groovy is okay!"
].contains(replaced)
// Use closure to replace text and use grouping.
// First closure parameter is complete string and following
// parameters are the groups.
def txt = "Generated on 30-10-2009 with Groovy."
def replacedTxt = txt.replaceAll(/.*(\d{2}-\d{2}-\d{4}).*(Gr.*)./) { all, date, lang ->
def dateObj = Date.parse('dd-MM-yyyy', date)
"The text '$all' was created with $lang on a ${dateObj.format('EEEE')}."
}
assert "The text 'Generated on 30-10-2009 with Groovy.' was created with Groovy on a Friday." == repla\
cedTxt
Original post written on October 22, 2009
Replace Characters in a String with CollectReplacements
We can use the collectReplacements(Closure)
method to replace characters in a String
. We pass a closure to the method and the closure is invoked for each character in the String
value. If we return null
the character is not transformed, otherwise we can return the replacement character.
def s = 'Gr00vy is gr8'
def replacement = {
// Change 8 to eat
if (it == '8') {
'eat'
// Change 0 to o
} else if (it == '0') {
'o'
// Do not transform
} else {
null
}
}
assert s.collectReplacements(replacement) == 'Groovy is great'
Code written with Groovy 2.1.6
Original post written on September 6, 2013
Text Translation
In Groovy 1.7.3 the tr()
method is added to the String
class. With this method we can do translations in String values. We define a source set of characters that need to be replaced by a replacement set of characters. We can also use a regular expression style (remember it is not a real regular expression) to define a range of characters.
If the replacement set is smaller than the source set, than the last character of the replacement set is used for the remaining source set characters.
// Source set and replacement set are equal size.
assert 'I 10v3 9r00vy' == 'I love Groovy'.tr('loeG', '1039')
// Regular expression style range
assert 'mrHAKI' == 'mrhaki'.tr('a-k', 'A-K')
// Replacement set is smaller than source set.
assert 'Gr8888' == 'Groovy'.tr('ovy', '8')
Original post written on June 15, 2010
Remove Parts of a String
Groovy has added the minus()
method to the String class. And because the minus()
method is used by the -
operator we can remove parts of a String with this operator. The argument can be a String or a regular expression Pattern. The first occurrence of the String or Pattern is then removed from the original String.
def s = 'Groovy and Strings are fun and versatile.'
assert 'Groovy and Strings are fun' == s - ' and versatile.'
assert 'Groovy and Strings are fun.' == s.minus(" and versatile")
assert 'Groovy Strings are fun and versatile.' == s - ~/\b\w{3}\b/
Original post written on November 2, 2009
Remove Part of String With Regular Expression Pattern
Since Groovy 2.2 we can subtract a part of a String value using a regular expression pattern. The first match found is replaced with an empty String. In the following sample code we see how the first match of the pattern is removed from the String:
// Define regex pattern to find words starting with gr (case-insensitive).
def wordStartsWithGr = ~/(?i)\s+Gr\w+/
assert ('Hello Groovy world!' - wordStartsWithGr) == 'Hello world!'
assert ('Hi Grails users' - wordStartsWithGr) == 'Hi users'
// Remove first match of a word with 5 characters.
assert ('Remove first match of 5 letter word' - ~/\b\w{5}\b/) == 'Remove match of 5 letter word'
// Remove first found numbers followed by a whitespace character.
assert ('Line contains 20 characters' - ~/\d+\s+/) == 'Line contains characters'
Code written with Groovy 2.2.
Original post written on November 18, 2013
Taking Or Dropping Number Of Characters From A String
Groovy adds a lot of methods to the Java String
class. For example we can use the take
method to get a certain number of characters from the start of a string value. With the drop
method we remove a given number of characters from the start of the string. In Groovy 3 we can now also take and drop a certain number of characters from the end of a string using the methods takeRight
and dropRight
.
In the following example we see how we can use the methods:
def s = "Groovy rocks!"
// Drop first 7 characters.
assert s.drop(7) == "rocks!"
// Drop last 7 characters.
assert s.dropRight(7) == "Groovy"
// Take first 6 characters.
assert s.take(6) == "Groovy"
// Take last 6 characters.
assert s.takeRight(6) == "rocks!"
Written with Groovy 3.0.2.
Original post written on March 10, 2020
Splitting Strings
In Java we can use the split()
method of the String
class or the StringTokenizer
class to split strings. Groovy adds the methods split()
and tokenize()
to the String
class, so we can invoke them directly on a string. The split()
method return a String[]
instance and the tokenize()
method return a List
. There is also a difference in the argument we can pass to the methods. The split()
method takes a regular expression string and the tokenize()
method will use all characters as delimiter.
def s = '''\
username;language,like
mrhaki,Groovy;yes
'''
assert s.split() instanceof String[]
assert ['username;language,like', 'mrhaki,Groovy;yes'] == s.split() // Default split on whitespace. (\
\t\n\r\f)
assert ['username', 'language', 'like', 'mrhaki', 'Groovy', 'yes'] == s.split(/(;|,|\n)/) // Split ar\
gument is a regular expression.
def result = []
s.splitEachLine(",") {
result << it // it is list with result of split on ,
}
assert ['username;language', 'like'] == result[0]
assert ['mrhaki', 'Groovy;yes'] == result[1]
assert s.tokenize() instanceof List
assert ['username;language,like', 'mrhaki,Groovy;yes'] == s.tokenize() // Default tokenize on whitesp\
ace. ( \t\n\r\f)
assert ['username', 'language', 'like', 'mrhaki', 'Groovy', 'yes'] == s.tokenize("\n;,") // Argument \
is a String with all tokens we want to tokenize on.
Run script on Groovy web console.
Original post written on November 5, 2009
Get Unique Characters in a String
Groovy adds the toSet()
method to the String
class in version 1.8. With this method we get a Set of unique String values from the original String value.
String s = 'Groovy is gr8!'
assert s.toSet().sort().join() == ' !8Ggiorsvy'
Original post written on April 27, 2011
Partial Matches
Groovy 2.0 adds the matchesPartially()
method to the Matcher
class. This method returns true if a String value matches the pattern or if it matches the first part of the pattern. So with the matchesPartially()
we get the result true
if a String value or a longer String value matches the pattern.
def identification = /[A-Z]{2}\-\d{3,5}/
def matcher = 'AB-1234' =~ identification
assert matcher.matchesPartially()
matcher = 'XY-90' =~ identification
assert matcher.matchesPartially()
matcher = 'HA' =~ identification
assert matcher.matchesPartially()
matcher = 'A-431' =~ identification
assert !matcher.matchesPartially()
matcher = 'YK-901201' =~ identification
assert !matcher.matchesPartially()
Original post written on June 28, 2012
Transform String into Enum
After reading Groovy, State of the Union - Groovy Grails eXchange 2010 by Guillaume Laforge I discovered that in Groovy 1.7.6 we can transform a String into a Enum value. We can use type coersion or the as
keyword to turn a String or GString into a corresponding Enum value (if possible).
enum Compass {
NORTH, EAST, SOUTH, WEST
}
// Coersion with as keyword.
def north = 'NORTH' as Compass
assert north == Compass.NORTH
// Coersion by type.
Compass south = 'south'.toUpperCase()
assert south == Compass.SOUTH
def result = ['EA', 'WE'].collect {
// Coersion of GString to Enum.
"${it}ST" as Compass
}
assert result[0] == Compass.EAST
assert result[1] == Compass.WEST
Original post written on December 16, 2010
String Continuation
Groovy makes writing concise code easy,. We can use the continuation character (\) in a String to split up the definition over multiple lines.
def name ='mrhaki'
def s = "This is not a multiline\
String, $name, but the continuation\
character (\\) makes it more readable."
assert 'This is not a multiline String, mrhaki, but the continuation character (\\) makes it more read\
able.' == s
Original post written on November 29, 2010
Strip Leading Spaces from Lines
Multiline strings are very useful in Groovy. But sometimes they can mess up our code formatting especially if we want to use the multiline string's value literally. If our lines cannot start with spaces we must define our multiline string that way:
class Simple {
String multi() {
'''\
Multiline string
with simple 2 space
indentation.'''
}
// Now in Groovy 1.7.3:
String multi173() {
'''\
Multiline string
with simple 2 space
indentation.'''.stripIndent()
}
}
Since Groovy 1.7.3 we can strip leading spaces from such lines, so we can align the definition of our multiline string the way we want with the stripIndent()
method. Groovy finds the line with the least spaces to determine how many spaces must be removed from the beginning of the line. Or we can tell the stripIndent()
method how many characters must be removed from the beginning of the line.
def multi = '''\
Multiline string
with simple 2 space
indentation.'''
assert '''\
Multiline string
with simple 2 space
indentation.''' == multi.stripIndent()
assert '''\
ine string
imple 2 space
ation.''' == multi.stripIndent(8) // We can define the number of characters ourselves as well.
Original post written on June 14, 2010
Strip Leading Spaces from Lines with Margin
Since Groovy 1.7.3 we can use the stripMargin()
method to strip characters up to and including a margin character from multiline strings. The default character is the pipe symbol (|), but we can pass a parameter to the method and use a custom character.
def s = '''\
|Groovy
|Grails
|Griffon'''
assert '''\
Groovy
Grails
Griffon''' == s.stripMargin()
def s1 = '''\
* Gradle
* GPars
* Spock'''
assert '''\
Gradle
GPars
Spock''' == s1.stripMargin("* ")
Original post written on June 20, 2010
Formatted Strings with sprintf
Groovy adds the sprintf()
method to the Object
class. This means we can use the method in all of the classes, because it is defined at the top of the hierarchy. The sprintf()
method uses the Java Formatter syntax to format values. We get a String as a result from the method.
assert 'Groovy is cool!' == sprintf( '%2$s %3$s %1$s', ['cool!', 'Groovy', 'is'])
assert '00042' == sprintf('%05d', 42)
Original post written on December 11, 2009
Expand or Unexpand Space or Tab Delimited Text
Groovy 1.7.3 adds new functionality to the String
class. For example we can use the expand()
method to expand tabs in a String
to spaces with a default tab stop size of 8. We can use a parameter to use a different tab stop size. But we can also go the other way around.
So if we have a tabular text based on spaces we can convert the String
to a tab separated String
. Here the default tab stop size is also 8, but we can use the parameter to define a different tab stop size.
// Simple ruler to display 0 up to 30
def ruler = (0..30).inject('\n') { result, c ->
result += (c % 10)
}
def stringWithTabs = 'Groovy\tGrails\tGriffon'
println ruler
println stringWithTabs.expand() // default tab stop is 8
println stringWithTabs.expand(10) // tab stop is 10
// Output:
// 0123456789012345678901234567890
// Groovy Grails Griffon
/ /Groovy Grails Griffon
assert 'Groovy Grails Griffon' == stringWithTabs.expand()
assert 'Groovy Grails Griffon' == stringWithTabs.expand(10)
def stringWithSpaces = 'Hubert Klein Ikkink'
def stringWithSpaces10 = 'Hubert Klein Ikkink'
println ruler
println stringWithSpaces
println stringWithSpaces10
// Output:
// 0123456789012345678901234567890
// Hubert Klein Ikkink
// Hubert Klein Ikkink
assert 'Hubert\tKlein\tIkkink' == stringWithSpaces.unexpand()
assert 'Hubert\tKlein\tIkkink' == stringWithSpaces10.unexpand(10)
Original post written on June 14, 2010
Normalize and Denormalize Linefeeds and Carriage Returns
Each platform where we can run Java and Groovy applications has different line separators. Groovy adds two methods to the String
class to convert the specific platform line separator to linefeeds and vica versa.
def text = 'First line\r\nSecond line\r\n'
def textNormalized = text.normalize()
def platformLineSeparator = System.properties['line.separator']
assert 'First line\nSecond line\n' == textNormalized
assert "First line${platformLineSeparator}Second line${platformLineSeparator}" == textNormalized.denor\
malize()
Original post written on January 2, 2010
Base64 URL and Filename Safe Encoding
Groovy supported Base64 encoding for a long time. Since Groovy 2.5.0 we can also use Base64 URL and Filename Safe encoding to encode a byte array with the method encodeBase64Url
. The result is a Writable
object. We can invoke the toString
method on the Writable
object to get a String
value. An encoded String
value can be decoded using the same encoding with the method decodeBase64Url
that is added to the String
class.
In the following example Groovy code we encode and decode a byte array:
import static java.nio.charset.StandardCharsets.UTF_8
def message = 'Groovy rocks!'
// Get bytes array for String using UTF8.
def messageBytes = message.getBytes(UTF_8)
// Encode using Base64 URL and Filename encoding.
def messageBase64Url = messageBytes.encodeBase64Url().toString()
// Encode using Base64 URL and Filename encoding with padding.
def messageBase64UrlPad = messageBytes.encodeBase64Url(true).toString()
assert messageBase64Url == 'R3Jvb3Z5IHJvY2tzIQ'
assert messageBase64UrlPad == 'R3Jvb3Z5IHJvY2tzIQ=='
// Decode the String values.
assert new String(messageBase64Url.decodeBase64Url()) == 'Groovy rocks!'
assert new String(messageBase64UrlPad.decodeBase64Url()) == 'Groovy rocks!'
Written with Groovy 2.5.0.
Original post written on June 11, 2018
Calculate MD5 And SHA Hash Values
Groovy adds a lot of useful methods to the String
class. Since Groovy 2.5.0 we can even calculate MD5 and SHA hash values using the methods md5
and digest
. The md5
method create a hash value using the MD5 algorithm. The digest
method accepts the name of the algorithm as value. These values are dependent on the available algorithms on our Java platform. For example the algorithms MD2, MD5, SHA-1, SHA-256, SHA-384 and SHA-512 are by default available.
In the next example we use the md5
and digest
methods on a String
value:
def value = 'IamASecret'
def md5 = value.md5()
// We can provide hash algorithm with digest method.
def md2 = value.digest('MD2')
def sha1 = value.digest('SHA-1')
def sha256 = value.digest('SHA-256')
assert md5 == 'a5f3147c32785421718513f38a20ca44'
assert md2 == '832cbe3966e186194b1203c00ef47488'
assert sha1 == '52ebfed118e0a411e9d9cbd60636fc9dea718928'
assert sha256 == '4f5e3d486d1fd6c822a81aa0b93d884a2a44daf2eb69ac779a91bc76de512cbe'
Written with Groovy 2.5.0.
Original post written on June 12, 2018
Converting Byte Array to Hex String
To convert a byte[]
array to a String
we can simply use the new String(byte[])
constructor. But if the array contains non-printable bytes we don't get a good representation. In Groovy we can use the method encodeHex()
to transform a byte[]
array to a hex String
value. The byte
elements are converted to their hexadecimal equivalents.
final byte[] printable = [109, 114, 104, 97, 107, 105]
// array with non-printable bytes 6, 27 (ACK, ESC)
final byte[] nonprintable = [109, 114, 6, 27, 104, 97, 107, 105]
assert new String(printable) == 'mrhaki'
assert new String(nonprintable) != 'mr haki'
// encodeHex() returns a Writable
final Writable printableHex = printable.encodeHex()
assert printableHex.toString() == '6d7268616b69'
final nonprintableHex = nonprintable.encodeHex().toString()
assert nonprintableHex == '6d72061b68616b69'
// Convert back
assert nonprintableHex.decodeHex() == nonprintable
Code written with Groovy 2.2.1
Original post written on April 3, 2014
GString as Writable
The Groovy API has the interface Writable. Classes that implement this interface are capable of writing their selves to a java.io.Writer
object. The interface has one method writeTo()
where the code is that writes the contents to a given Writer
instance. Most implementations will also use the implementation of the writeTo()
method in their toString()
implementation.
The GString implementation in Groovy also implements the Writable
interface. This means we can redirect the GString contents to some Writer
instance if we want to. In the following code we use a FileWriter
to write the contents of a GString to a file:
def data = [
new Expando(id: 1, user: 'mrhaki', country: 'The Netherlands'),
new Expando(id: 2, user: 'hubert', country: 'The Netherlands'),
]
data.each { userData ->
new File("${userData.id}.txt").withWriter('UTF-8') { fileWriter ->
// Use writeTo method on GString to save
// result in a file.
"User $userData.user lives in $userData.country".writeTo(fileWriter)
}
}
assert new File('1.txt').text == 'User mrhaki lives in The Netherlands'
assert new File('2.txt').text == 'User hubert lives in The Netherlands'
Code written with Groovy 2.2.2
Original post written on April 4, 2014
Closure as Writable
In a previous post we learned about the Writable
interface and how the GString implementation implements this interface. In Groovy we can also use a closure as an implementation of the Writable
interface. The Closure
class has the method asWritable()
that will return a version of the closure with an implementation of the writeTo()
method. The Writer
object that is used as an argument for the writeTo()
method will be passed as argument to the closure. The asWritable()
method also adds a toString()
implementation for the closure to return the result of a closure as a String
.
In the following code we write a sample make()
method. The make()
method return a Writable
closure. The closure is only executed when the writeTo()
or toString()
method is invoked.
Writable make(Map binding = [:], Closure template) {
// Use asWritable() to make the closure
// implement the Writable interface.
def writableTemplate = template.asWritable()
// Assing binding map as delegate so we can access
// the keys of the maps as properties in the
// closure context.
writableTemplate.delegate = binding
// Return closure as Writable.
writableTemplate
}
// Use toString() of Writable closure.
assert make { Writer out -> out << "Hello world!" }.toString() == 'Hello world!'
// Provide data for the binding.
// The closure is not executed when the
// make method is finished.
final writable = make(user:'mrhaki', { out ->
out.println "Welcome ${user},"
out.print "Today on ${new Date(year: 114, month: 3, date: 4).format('dd-MM-yyyy')}, "
out.println "we have a Groovy party!"
})
// We invoke toString() and now the closure
// is executed.
final result = writable.toString()
assert result == '''Welcome mrhaki,
Today on 04-04-2014, we have a Groovy party!
'''
// Append contents to a file.
// NOTE: The leftShift (<<) operator on File is implemented
// in Groovy to use the File.append() method.
// The append() method creates a new Writer and
// invokes the write() method which
// is re-implemented in Groovy if the argument
// is a Writable object. Then the writeTo() method
// is invoked:
// Writer.write(Writable) becomes Writable.writeTo(Writer).
// So a lot of Groovy magic allows us to use the following one-liner
// and still the writeTo() method is used on Writable.
new File('welcome.txt') << writable
assert new File('welcome.txt').text == '''Welcome mrhaki,
Today on 04-04-2014, we have a Groovy party!
'''
Code written with Groovy 2.2.2
Original post written on April 4, 2014
Maps
Check if Maps are Equal
With Groovy 1.8 the equals()
method is added to Map
. This means we can check if maps are equals. They are equals if both maps have the same size, and keys and values are the same.
def map1 = [user: 'mrhaki', likes: 'Groovy', age: 37]
def map2 = [age: 37.0, likes: 'Groovy', user: 'mrhaki']
def map3 = [user: 'Hubert Klein Ikkink', likes: 'Groovy']
assert map1.equals(map2)
assert map1 == map2
assert !map1.equals(map3)
assert map2 != map3
Original post written on April 27, 2011
Sorting a Map
Maps don't have an order for the elements, but we may want to sort the entries in the map. Since Groovy 1.7.2 we can use the sort()
method which uses the natural ordering of the keys to sort the entries. Or we can pass a Comparator to the sort()
method to define our own sorting algorithm for the keys.
def m = [sort: 'asc', name: 'test', paginate: true, max: 100]
def expectedKeys = ['max', 'name', 'paginate', 'sort']
assert expectedKeys == m.sort()*.key // Since 1.7.2
assert expectedKeys == m.sort( { k1, k2 -> k1 <=> k2 } as Comparator )*.key // Since 1.7.2
// Sorting before Groovy 1.7.2
assert expectedKeys == new TreeMap(m)*.key
assert expectedKeys == m.sort { e1, e2 -> e1.key <=> e2.key }*.key // Sort by closure.
Original post written on April 20, 2010
Turn a List into a Map
With Groovy we can use the values of an Object
array and transform them to a map with the toSpreadMap()
method. The array must have an even number of elements, because the odd elements are the keys for the new map and the even numbers are the values for the keys. The SpreadMap
object, which now contains the keys and values, is an immutable map, so we cannot change the contents once we have created the map.
def list = ['key', 'value', 'name', 'mrhaki'] as Object[]
def map = list.toSpreadMap()
assert 2 == map.size()
assert 'value' == map.key
assert 'mrhaki' == map['name']
Original post written on January 4, 2010
Complex Keys in Maps
In Groovy we can use non-string keys for maps. We only have to place parenthesis around the key to make it work. This way we can use variables and types like Date and Boolean as keys for our map. When we use parenthesis around the key when using the . notation the key is converted to a String, otherwise the key is not converted and keeps it type.
def key = 100 // Variable to be used a key.
def m = [
(new Date(109, 11, 1)): 'date key',
(-42): 'negative number key',
(false): 'boolean key',
(key): 'variable key'
]
m.(true) = 'boolean key' // Key is converted to String.
m.(2 + 2) = 'number key'
m[(key + 1)] = 'number key' // Key keeps to be Integer.
assert 'date key' == m[new Date(109, 11, 1)]
assert 'negative number key' == m.get(-42)
assert 'boolean key' == m[(false)]
assert 'variable key' == m[100]
assert 'variable key' == m.getAt(key)
assert 'boolean key' == m['true'] // Key is String so we can use it to get the value.
assert 'number key' == m.'4'
assert 'number key' == m.get(101)
Original post written on November 7, 2009
Use inject Method on a Map
The inject()
method is since Groovy 1.8.1 also available for Map objects. The closure arguments accepts two or three arguments. With the three-argument variant we get the key and value separately as arguments. Otherwise we get a map entry as closure argument.
// 3-argument closure with key, value.
def m = [user: 'mrhaki', likes: 'Groovy']
def sentence = m.inject('Message: ') { s, k, v ->
s += "${k == 'likes' ? 'loves' : k} $v "
}
assert sentence.trim() == 'Message: user mrhaki loves Groovy'
// 2-argument closure with entry.
def map = [sort: 'name', order: 'desc']
def equalSizeKeyValue = map.inject([]) { list, entry ->
list << (entry.key.size() == entry.value.size())
}
assert equalSizeKeyValue == [true, false]
Original post written on September 27, 2011
Intersect Maps
Since Groovy 1.7.4 we can intersect two maps and get a resulting map with only the entries found in both maps.
def m1 = [a: 'Groovy', b: 'rocks', c: '!']
def m2 = [a: 'Groovy', b: 'rocks', c: '?', d: 'Yes!']
assert [a: 'Groovy', b: 'rocks'] == m1.intersect(m2)
assert [1: 1.0, 2: 2] == [1: 1.0, 2: 2].intersect([1: 1, 2: 2.0])
Original post written on August 9, 2010
Subtracting Map Entries
Groovy 1.7.4 adds the minus()
method to the Map
class. The result is a new map with the entries of the map minus the same entries from the second map.
def m1 = [user: 'mrhaki', age: 37]
def m2 = [user: 'mrhaki', name: 'Hubert']
def m3 = [user: 'Hubert', age: 37]
assert [age: 37] == m1 - m2
assert [user: 'mrhaki'] == m1 - m3
Original post written on August 9, 2010
Process Map Entries in Reverse
Since Groovy 1.7.2 we can loop through a Map
in reverse with the reverseEach()
. The order in which the content is processed is not guaranteed with a Map
. If we use a TreeMap
the natural ordering of the keys of the map is used.
def reversed = [:]
[a: 1, c: 3, b: 2].reverseEach { key, value ->
reversed[key] = value ** 2
}
assert [b: 4, c: 9, a: 1] == reversed
// TreeMap uses natural ordering of keys, so
// reverseEach starts with key 'c'.
def tree = [a: 10, c: 30, b: 20] as TreeMap
def reversedMap = [:]
tree.reverseEach {
reversedMap[it.key] = it.value * 2
}
assert [c: 60, b: 40, a: 20] == reversedMap
Original post written on August 24, 2010
Getting a Submap from a Map
To get only a subset of a map we can use the subMap()
method. We provide a list of keys as parameter to define which elements from the map we want returned.
def map = [name: 'mrhaki', country: 'The Netherlands', blog: true, languages: ['Groovy', 'Java']]
def keys = ['name', 'blog']
assert [name: 'mrhaki', blog: true] == map.subMap(keys)
def booleanKeys = map.findAll { it.value instanceof Boolean }.collect { it.key }
assert [blog: true] == map.subMap(booleanKeys)
def words = ['a': 'Apple', 'j': 'Java', 'g': 'Groovy', 'c': 'Cool']
def range = 'c'..'h' // Range is also a list and can be used here.
def rangeWords = words.subMap(range).findAll{ it.value }
// words.subMap(range) returns [c:Cool, d:null, e:null, f:null, g:Groovy, h:null]
// so we use the findAll method to filter out all null values.
assert ['c': 'Cool', 'g': 'Groovy'] == rangeWords
Original post written on October 29, 2009
Grouping Map Elements
In a previous Groovy Goodness post we learned how to use the groupBy
method on collections. The Map
class has an extra method: groupEntriesBy
. We must provide a closure for this method to define how we want the elements of the map to be grouped. The result is a new Map
with keys and a list of Map$Entry
objects for each key. This is different from the result of the groupBy
method. Because then we get a Map
with keys and a Map
for each key.
// A simple map.
def m = [q1: 'Groovy', sort: 'desc', q2: 'Grails']
// Closure we use to define the grouping.
// We want all keys starting with 'q' grouped together
// with the key 'params', all other keys are not grouped.
def groupIt = { key, value ->
if (key.startsWith('q')) {
'params'
} else {
key
}
}
// Use groupEntriesBy.
def groupEntries = m.groupEntriesBy(groupIt)
assert 2 == groupEntries.size()
assert groupEntries.params & groupEntries.sort
assert 'desc' == groupEntries.sort[0].value // Key for a list of Map$Entry objects.
assert 2 == groupEntries.params.size()
assert 'Groovy' == groupEntries.params[0].value
assert 'q1' == groupEntries.params[0].key
assert 'Grails' == groupEntries.params.find { it.key == 'q2' }.value
assert groupEntries.params instanceof ArrayList
assert groupEntries.params[0] instanceof Map$Entry
// Use groupBy.
def group = m.groupBy(groupIt)
assert 2 == group.size()
assert group.params & group.sort
assert 'desc' == group.sort.sort // Key for Map with key/value pairs.
assert 2 == group.params.size()
assert 'Groovy' == group.params.q1
assert 'q1' == group.params.keySet().toArray()[0]
assert 'Grails' == group.params.q2
assert group.params instanceof Map
assert group.params.q1 instanceof String
Original post written on October 14, 2009
Get Value from Map or a Default Value
The get()
method in the Groovy enhanced Map
interface accepts two parameters. The first parameter is the name of the key we want to get a value for. And the second parameter is the default value if there is no value for the key.
// Simple map.
def m = [name: 'mrhaki', language: 'Groovy']
assert 'mrhaki' == m.getAt('name')
assert 'mrhaki' == m['name']
assert 'Groovy' == m.language
assert 'mrhaki' == m."name"
assert 'mrhaki' == m.get('name') // We can omit the default value if we know the key exists.
assert 'Groovy' == m.get('language', 'Java')
assert null == m.get('expression') // Non-existing key in map.
assert 'rocks' == m.get('expression', 'rocks') // Use default value, this also creates the key/value \
pair in the map.
assert 'rocks' == m.get('expression')
assert [name: 'mrhaki', language: 'Groovy', expression: 'rocks'] == m
Run this script in Groovy web console.
Original post written on November 3, 2009
Map with Default Values
In Groovy we can create a map and use the withDefault()
method with a closure to define default values for keys that are not yet in the map. The value for the key is then added to the map, so next time we can get the value from the map.
def m = [start: 'one'].withDefault { key ->
key.isNumber() ? 42 : 'Groovy rocks!'
}
assert 'one' == m.start
assert 42 == m['1']
assert 'Groovy rocks!' == m['I say']
assert 3 == m.size()
// We can still assign our own values to keys of course:
m['mrhaki'] = 'Hubert Klein Ikkink'
assert 'Hubert Klein Ikkink' == m.mrhaki
assert 4 == m.size()
Original post written on July 14, 2010
Determine Min and Max Entries in a Map
Since Groovy 1.7.6 we can use the min()
and max()
methods on a Map
. We use a closure to define the condition for a minimum or maximum value. If we use two parameters in the closure we must do a classic comparison. We return a negative value if the first parameters is less than the second, zero if they are both equal, or a positive value if the first parameter is greater than the second parameter. If we use a single parameter we can return a value that is used as Comparable
for determining the maximum or minimum entry in the Map
.
def money = [cents: 5, dime: 2, quarter: 3]
// Determine max entry.
assert money.max { it.value }.value == 5
assert money.max { it.key }.key == 'quarter' // Use String comparison for key.
assert money.max { a, b ->
a.key.size() <=> b.key.size()
}.key == 'quarter' // Use Comparator and compare key size.
// Determine min entry.
assert money.min { it.value }.value == 2
assert money.min { it.key }.key == 'cents' // Use String comparison for key.
assert money.min { a, b ->
a.key.size() <=> b.key.size()
}.key == 'dime' // Use Comparator and compare key size.
Original post written on December 16, 2010
Represent Map As String
Groovy adds to Map
objects the toMapString
method. With this method we can have a String representation of our Map
. We can specify an argument for the maximum width of the generated String
. Groovy will make sure at least the key/value pairs are added as a pair, before adding three dots (...
) if the maximum size is exceeded.
def course = [
name: 'Groovy 101',
teacher: 'mrhaki',
location: 'The Netherlands']
assert course.toMapString(15) == '[name:Groovy 101, ...]'
assert course.toMapString(25) == '[name:Groovy 101, teacher:mrhaki, ...]'
As mentioned in a previous post we can use the toListString
method to represent a List
as a String
:
def names = ['mrhaki', 'hubert']
assert names.toListString(5) == '[mrhaki, ...]'
Written with Groovy 2.4.7.
Original post written on June 21, 2016
Turn A Map Or List As String To Map Or List
In a previous post we learned how to use the toListString
or toMapString
methods. With these methods we create a String representation of a List
or Map
object. With a bit of Groovy code we can take such a String
object and turn it into a List
or Map
again.
In the following code snippet we turn the String
value [abc, 123, Groovy rocks!]
to a List
with three items:
// Original List with three items.
def original = ['abc', 123, 'Groovy rocks!']
// Create a String representation:
// [abc, 123, Groovy rocks!]
def listAsString = original.toListString()
// Take the String value between
// the [ and ] brackets, then
// split on , to create a List
// with values.
def list = listAsString[1..-2].split(', ')
assert list.size() == 3
assert list[0] == 'abc'
assert list[1] == '123' // String value
assert list[2] == 'Groovy rocks!'
We can do something similar for a String
value representing a map structure:
// Original Map structure.
def original = [name: 'mrhaki', age: 42]
// Turn map into String representation:
// [name:mrhaki, age:42]
def mapAsString = original.toMapString()
def map =
// Take the String value between
// the [ and ] brackets.
mapAsString[1..-2]
// Split on , to get a List.
.split(', ')
// Each list item is transformed
// to a Map entry with key/value.
.collectEntries { entry ->
def pair = entry.split(':')
[(pair.first()): pair.last()]
}
assert map.size() == 2
assert map.name == 'mrhaki'
assert map.age == '42'
Written with Groovy 2.4.7.
Original post written on June 22, 2016