We can use either single- or double-quotes around strings:
assert 'hello, world' == "hello, world"
assert "Hello, Groovy's world" == 'Hello, Groovy\'s world'
assert 'Say "Hello" to the world' == "Say \"Hello\" to the world"
Backslashes can escape other characters in Strings. We can use letter codes (eg '\b') or octal codes (eg '\010'):
assert '\b' == '\010' assert '\t' == '\011' assert '\n' == '\012' assert '\f' == '\014' assert '\r' == '\015' assert '\\' == '\\'
To span multiple lines, use either triple quotes or a backslash at the end of the continuing lines to join them with the next:
assert '''hello,
world''' == 'hello,\nworld'
assert 'hello, \
world' == 'hello, world'
We can also use three double-quotes.
def text = """\
Good morning.
Good night again."""
When using double-quotes, either one or three, we can embed code within them using $. Here, they're called GStrings:
def name = 'Groovy'
assert "hello $name, how are you today?" == "hello Groovy, how are you today?"
Anything more complex than a variable name must be surrounded by curlies:
def a = 'How are you?'
assert "The phrase '$a' has length ${a.size()}" ==
"The phrase 'How are you?' has length 12"
We can change the variable's value in the GString:
def i= 1, list= []
3.times{ list<< "${i++}" }
assert list.join() == '123'
String methods
We can convert other objects in Groovy to their string representation in different ways:
def o= new Object()
assert String.valueOf( o ) == o.toString() assert String.valueOf( true ) == true.toString() assert String.valueOf( 'd' as char ) == ('d' as char).toString() assert String.valueOf( 7.5d ) == 7.5d.toString() assert String.valueOf( 8.4f ) == 8.4f.toString() assert String.valueOf( 13i ) == 13i.toString() assert String.valueOf( 14L ) == 14L.toString() assert String.valueOf( ['a', 'b', 'c'] ) == ['a', 'b', 'c'].toString()
To find the size and substrings:
def s= 'abcdefg'
assert s.length() == 7 && s.size() == 7
assert s.substring(2,5) == 'cde' && s.substring(2) == 'cdefg'
assert s.subSequence(2,5) == 'cde'
There's different ways to construct a string:
assert new String() == ''
assert new String('hello') == 'hello'
def minLowSurr= Character.MIN_LOW_SURROGATE,
minHighSurr= Character.MIN_HIGH_SURROGATE
def str= 'abc' + minHighSurr + minLowSurr + 'efg'
def ca= ['a', 'b', 'c', minHighSurr, minLowSurr, 'e', 'f', 'g'] as char[]
def ia= ['a', 'b', 'c', 0x10000, 'e', 'f', 'g'] as int[]
assert new String(ca) == str
assert new String(ca, 2, ca.size()-2) == str[2..-1]
assert new String(ia, 2, ia.size()-2) == str[2..-1]
def ca2= new char[8]
str.getChars(0, str.size(), ca2, 0)
assert ca2.size() == str.size()
ca2.eachWithIndex{ elt, i-> assert elt == str[i] }
def ca3= ['a', 'b', 'c', 'd', 'e'] as char[]
'abcde'.toCharArray().eachWithIndex{ it, i-> assert it == ca3[i] }
assert String.valueOf(ca3) == 'abcde' assert String.copyValueOf(ca3) == 'abcde' assert String.valueOf(ca3, 2, 2) == 'cd' assert String.copyValueOf(ca3, 2, 2) == 'cd'
We can pad and center strings:
assert 'hello'.padRight(8,'+').padLeft(10,'+') == '++hello+++'
assert 'hello'.padLeft(7).padRight(10) == ' hello '
assert 'hello'.center(10, '+').center(14, ' ') == ' ++hello+++ '
We can split a string into tokens:
assert 'he she\t it'.tokenize() == ['he', 'she', 'it']
assert 'he she\t it'.tokenize() ==
new StringTokenizer('he she\t it').collect{ it }
assert 'he,she;it,;they'.tokenize(',;') == ['he', 'she', 'it', 'they']
assert new StringTokenizer('he,she;it,;they', ',;').collect{ it } ==
'he,she;it,;they'.tokenize(',;')
assert new StringTokenizer('he,she,;it', ',;', true).collect{ it } ==
['he', ',', 'she', ',', ';', 'it']
Some additional methods:
assert 'abcde'.find{ it > 'b' } == 'c' assert 'abcde'.findAll{ it > 'b' } == ['c', 'd', 'e'] assert 'abcde'.findIndexOf{ it > 'c' } == 3
assert 'abcde'.every{ it < 'g' } && ! 'abcde'.every{ it < 'c' }
assert 'abcde'.any{ it > 'c' } && ! 'abcde'.any{ it > 'g' }
assert 'morning'.replace('n','t') == 'mortitg' &&
'boo'.replace('o', 'at') == 'batat' &&
'book'.replace('oo','ie') == 'biek'
assert 'EggS'.toLowerCase() == 'eggs' && 'EggS'.toUpperCase() == 'EGGS'
assert ' Bacon '.trim() == 'Bacon'
assert 'noodles'.startsWith('nood') && 'noodles'.endsWith('dles')
assert 'corn soup'.startsWith('rn', 2)
assert 'abc'.concat('def') == 'abcdef'
assert 'abcdefg'.contains('def')
assert ''.isEmpty() && ! 'abc'.isEmpty()
assert 'morning'.indexOf('n') == 3
assert 'morning'.indexOf('n', 4) == 5 assert 'morning'.indexOf('ni') == 3
assert 'morning'.indexOf('ni', 4) == -1 assert 'morning'.lastIndexOf('n') == 5
assert 'morning'.lastIndexOf('n', 4) == 3 assert 'morning'.lastIndexOf('ni') == 3
assert 'morning'.lastIndexOf('ni', 4) == 3
We can use operators on strings:
assert 'hello, ' + 'balloon' - 'lo' == 'hel, balloon'
assert 'hello, balloon' - 'abc' == 'hello, balloon'
assert 'hello, '.plus('balloon').minus('lo') == 'hel, balloon'
assert 'value is ' + true == 'value is true' &&
'value is ' + 1.54d == 'value is 1.54' &&
'value is ' + 7 == 'value is 7' assert 7 + ' is value' == '7 is value'
assert 'telling true lies' - true == 'telling lies' &&
'week has 7 days' - 7 == 'week has days'
assert 'a' * 3 == 'aaa' && 'a'.multiply(3) == 'aaa'
assert 'hello'.reverse() == 'olleh'
assert 'hello'.count('l') == 2
assert 'abc'.collect{ it * 2 } == ['aa', 'bb', 'cc']
def s= [], t= [:]
'abc'.each{ s << it }
'abc'.eachWithIndex{ elt, i-> t[i]= elt }
assert s == ['a', 'b', 'c'] && t == [0:'a', 1:'b', 2:'c']
assert 'abcde'.toList() == ['a', 'b', 'c', 'd', 'e']
assert 'abc'.next() == 'abd' && 'abc'.previous() == 'abb'
We can subscript strings just as we can lists, except of course strings are read-only:
assert 'abcdefg'[ 3 ] == 'd'
assert 'abcdefg'.getAt( 3 ) == 'd' assert 'abcdefg'.charAt( 3 ) == 'd' assert 'abcdefg'[ 3..5 ] == 'def'
assert 'abcdefg'.getAt( 3..5 ) == 'def'
assert 'abcdefg'[ 1, 3, 5, 6 ] == 'bdfg'
assert 'abcdefg'[ 1, *3..5 ] == 'bdef'
assert 'abcdefg'[ 1, 3..5 ] == 'bdef'
assert 'abcdefg'[-5..-2] == 'cdef'
assert 'abcdefg'.getAt( [ 1, *3..5 ] ) == 'bdef'
assert 'abcdefg'.getAt( [ 1, 3..5 ] ) == 'bdef'
assert 'abcde' == 'ab' + 'c' + 'de'
assert 'abcde'.equals('ab' + 'c' + 'de') assert 'abcde'.contentEquals('ab' + 'c' + 'de') assert 'AbcdE'.equalsIgnoreCase('aBCDe')
assert 'abcde' < 'abcdf' && 'abcde' < 'abcdef'
assert 'abcde'.compareTo('abcdf') == -1 && 'abcde'.compareTo('abcdef') == -1
assert 'AbcdEF'.compareToIgnoreCase('aBCDe') == 1
assert 'AbcdE'.compareToIgnoreCase('aBCDef') == -1
assert Collections.max( 'abC'.toList(), String.CASE_INSENSITIVE_ORDER ) == 'C'
assert Collections.min(
['abC', 'ABd', 'AbCd'], String.CASE_INSENSITIVE_ORDER ) == 'abC'
assert 'abcde'.regionMatches(2, 'ccccd', 3, 2)
assert 'abcDE'.regionMatches(true, 2, 'CCCCd', 3, 2)
We can format values into a string, using format():
assert String.format('%1$8s', 'hello') == ' hello'
assert String.format('%2$6s,%1$2s', 'a', 'hello') == ' hello, a'
assert String.format('%1$2s', 7, 'd') == ' 7'
assert String.format('%1s,%2s', null, 'null') == 'null,null'
assert String.format('%1$2.4s', 'hello') == 'hell'
assert String.format('%1$c,%2$3c', 65, 66 as byte) == 'A, B'
assert String.format('%-3c', 67 as short) == 'C '
assert String.format('%c', 'D' as char) == 'D'
assert String.format('hello %n world %%') == 'hello \r\n world %'
assert String.format('%b, %b, %b, %b, %b, %b',
null, true, false, 0, 1, new Object()) ==
'false, true, false, true, true, true'
StringBuffers
A StringBuffer is a mutable string. (But from Java 5.0 onwards, we should use a StringBuilder instead, because StringBuffers are normally reserved for multi-threaded processing.)
def sb1= new StringBuffer(),
sb2= new StringBuffer('Hello'),
sb3= new StringBuffer(sb2)
assert sb1.toString() == '' &&
sb2.toString() == 'Hello' &&
sb2.toString() == sb3.toString()
To find the size and substrings:
def sb= new StringBuffer('abcdefg')
assert sb.size() == 7 && sb.length() == 7 sb.length= 6 assert sb.toString() == 'abcdef'
assert sb.reverse().toString() == 'fedcba'
assert sb.toString() == 'fedcba' assert sb.substring(2) == 'dcba' assert sb.substring(2, 5) == 'dcb' assert sb.subSequence(2, 5) == 'dcb' assert sb + 'zyx' == 'fedcbazyx'
To append to a StringBuffer:
def sb1= new StringBuffer()
sb1 << 'abc'
sb1 << 'def' << 'ghi' sb1.leftShift('jkl') sb1.append('mno') sb1.append( ['p', 'q', 'r'] as char[] )
sb1.append( ['r', 's', 't', 'u', 'v'] as char[], 1, 3 )
assert sb1.toString() == 'abcdefghijklmnopqrstu'
Note that << doesn't yet work with StringBuilders.
If we append to a String, a StringBuffer is returned:
def s= 'foo'
s= s << 'bar'
assert s.class == StringBuffer && s.toString() == 'foobar'
As with strings, we can subscript a StringBuffer, returning a string:
def sb= new StringBuffer('abcdefg')
assert sb[ 3 ] == 'd'
assert sb[ 3 ].class == String
assert sb.getAt( 3 ) == 'd' assert sb.charAt( 3 ) == 'd' assert sb[ 3..5 ] == 'def'
assert sb[ 1, 3, 5, 6 ] == 'bdfg'
assert sb[ 1, 3..5 ] == 'bdef'
assert sb[-5..-2] == 'cdef'
sb[ 3..5 ] = 'xy' assert sb.toString() == 'abcxyg'
sb.putAt( 2..4, 'z' ) assert sb.toString() == 'abzg'
sb.setCharAt(1, 'm' as char) assert sb.toString() == 'amzg'
We can insert into, replace within, and delete from StringBuffers using methods:
def sb= new StringBuffer('hello park')
sb.delete(4, 7)
assert sb.toString() == 'hellark'
sb.deleteCharAt(3)
assert sb.toString() == 'helark'
def ca= new char[6]
sb.getChars(2, 5, ca, 1)
(['\0', 'l', 'a', 'r', '\0', '\0'] as char[]).
eachWithIndex{ elt, i-> assert ca[i] == elt }
sb.insert(4, 'se')
assert sb.toString() == 'helaserk'
sb.insert(4, new StringBuffer('ct ') )
assert sb.toString() == 'helact serk'
sb.insert(10, ['i', 'c'] as char[] )
assert sb.toString() == 'helact serick'
sb.insert(6, ['m', 'a', 'l', 't'] as char[], 1, 2)
assert sb.toString() == 'helactal serick'
sb.insert(10, 'snapla', 3, 5) assert sb.toString() == 'helactal splerick'
sb.replace(4, 13, 'dor') assert sb.toString() == 'heladorrick'
We can find the index of substrings:
def sb= new StringBuffer('hello elm')
assert sb.indexOf('el') == 1
assert sb.indexOf('el', 3) == 6 assert sb.lastIndexOf('el') == 6
assert sb.lastIndexOf('el', 3) == 1
Some miscellaneous methods:
def s= new String( new StringBuffer('abcdefg') )
assert s == 'abcdefg'
assert s.contains('def')
assert s.contentEquals('abcdefg')
assert s.contentEquals( new StringBuffer('abcdefg') )
def s2= s.replace('def', 'xyz')
assert s2 == 'abcxyzg'
We can enquire of code points in a String or StringBuffer using methods on them, just as we can with methods on Character:
def minLowSurr= Character.MIN_LOW_SURROGATE,
minHighSurr= Character.MIN_HIGH_SURROGATE
def s1= 'abc'+ minHighSurr + minLowSurr +'efg'
assert s1.codePointAt(3) == 0x10000 assert s1.codePointAt(4) == minLowSurr assert s1.codePointAt(5) == 'e' as int
assert s1.codePointBefore(4) == minHighSurr
assert s1.codePointBefore(5) == 0x10000
assert s1.codePointCount(1, 5) == 3
assert s1.offsetByCodePoints(1, 3) == 5
def sb= new StringBuffer( 'abc'+ minHighSurr + minLowSurr +'efg' )
assert sb.codePointAt(5) == 'e' as int
assert sb.codePointBefore(4) == minHighSurr
assert sb.codePointCount(1, 5) == 3
assert sb.offsetByCodePoints(1, 3) == 5
sb.appendCodePoint(0x10000)
assert sb.toString() ==
'abc'+ minHighSurr + minLowSurr +'efg'+ minHighSurr + minLowSurr
We can manipulate the implementation of a StringBuffer:
def sb1= new StringBuffer() assert sb1.capacity() == 16
def sb2= new StringBuffer(5) assert sb2.capacity() == 5
sb2<< 'abc'
assert sb2.capacity() == 5 && sb2.size() == 3
sb2.trimToSize()
assert sb2.capacity() == 3
sb2.ensureCapacity(10)
assert sb2.capacity() == 10
def sb3= new StringBuffer(0) def cap= 0, caps=[]
100.times{
if((sb3<< 'a').capacity() != cap) caps<< (cap= sb3.capacity())
}
assert caps == [2, 6, 14, 30, 62, 126]
|
|