//---------------------------------------------------------------------------------- string = '\\n' // two characters, \ and an n assert string.size() == 2 string = "\n" // a "newline" character string = '\n' // a "newline" character string = "Jon 'Maddog' Orwant" // literal single quote inside double quotes string = 'Jon \'Maddog\' Orwant' // escaped single quotes string = 'Jon "Maddog" Orwant' // literal double quotes inside single quotes string = "Jon \"Maddog\" Orwant" // escaped double quotes string = ''' This is a multiline string declaration using single quotes (you can use double quotes) ''' //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // accessing substrings string = 'hippopotamus' start = 5; end = 7; endplus1 = 8 assert string.substring(start, endplus1) == 'pot' assert string[start..end] == 'pot' assert string.substring(start) == 'potamus' assert string[start..-1] == 'potamus' // String is immutable but new strings can be created in various ways assert string - 'hippo' - 'mus' + 'to' == 'potato' assert string.replace('ppopotam','bisc') == 'hibiscus' assert string.substring(0, 2) + 'bisc' + string[-2..-1] == 'hibiscus' // StringBuffer is mutable sb = new StringBuffer(string) sb[2..-3] = 'bisc' assert sb.toString() == 'hibiscus' // No exact pack/unpack equivalents exist in Groovy. Examples here use a custom // implementation to split an original string into chunks of specified length // the method is a modified version of the Java PLEAC version // get a 5-character string, skip 8, then grab 2 5-character strings // skipping the trailing spaces, then grab the rest data = 'hippopotamus means river horse' def fields = unpack('A5 x8 A5 x1 A5 x1 A*', data) assert fields == ['hippo', 'means', 'river', 'horse'] // On a Java 5 or 6 JVM, Groovy can also make use of Scanners: s = new Scanner(data) s.findInLine(/(.{5}).{8}(.{5}) (.{5}) (.*)/) m = s.match() fields = [] (1..m.groupCount()).each{ fields << m.group(it) } assert fields == ['hippo', 'means', 'river', 'horse'] // another scanner example similar to the javadoc example input = '1 fish 2 fish red fish blue fish' s = new Scanner(input).useDelimiter(/\s*fish\s*/) fields = [] 2.times{ fields << s.nextInt() } 2.times{ fields << s.next() } assert fields == [1, 2, 'red', 'blue'] // split at five characters boundaries String[] fivers = unpack('A5 ' * (data.length() / 5), data) assert fivers == ["hippo", "potam", "us me", "ans r", "iver ", "horse"] // chop string into individual characters assert 'abcd' as String[] == ['a', 'b', 'c', 'd'] string = "This is what you have" // Indexing forwards (left to right) // tens 000000000011111111112 // units +012345678901234567890 // Indexing backwards (right to left) // tens 221111111111000000000 // units 109876543210987654321- assert string[0] == 'T' assert string[5..6] == 'is' assert string[13..-1] == 'you have' assert string[-1] == 'e' assert string[-4..-1] == 'have' assert string[-8, -7, -6] == 'you' data = new StringBuffer(string) data[5..6] = "wasn't" ; assert data.toString() == "This wasn't what you have" data[-12..-1] = "ondrous" ; assert data.toString() == "This wasn't wondrous" data[0..0] = "" ; assert data.toString() == "his wasn't wondrous" data[-10..-1] = "" ; assert data.toString() == "his wasn'" string = "This wasn't wondrous" // check last ten characters match some pattern assert string[-10..-1] =~ /^t\sw.*s$/ string = 'This is a test' assert string[0..4].replaceAll('is', 'at') + string[5..-1] == 'That is a test' // exchange the first and last letters in a string string = 'make a hat' string = string[-1] + string[1..-2] + string[0] assert string == 'take a ham' // extract column with unpack string = 'To be or not to be' // skip 6, grab 6 assert unpack("x6 A6", string) == ['or not'] // forward 6, grab 2, backward 5, grab 2 assert unpack("x6 A2 X5 A2", string) == ['or', 'be'] assert cut2fmt([8, 14, 20, 26, 30]) == 'A7 A6 A6 A6 A4 A*' // utility method (derived from Java PLEAC version) def unpack(String format, String data) { def result = [] int formatOffset = 0, dataOffset = 0 int minDataOffset = 0, maxDataOffset = data.size() new StringTokenizer(format).each{ token -> int tokenLen = token.length() // count determination int count = 0 if (tokenLen == 1) count = 1 else if (token.charAt(1) == '*') count = -1 else count = token[1..-1].toInteger() // action determination char action = token.charAt(0) switch (action) { case 'A': if (count == -1) { start = [dataOffset, maxDataOffset].min() result.add(data[start..-1]) dataOffset = maxDataOffset } else { start = [dataOffset, maxDataOffset].min() end = [dataOffset + count, maxDataOffset].min() result.add(data[start..<end]) dataOffset += count } break case 'x': if (count == -1) dataOffset = maxDataOffset else dataOffset += count break case 'X': if (count == -1) dataOffset = minDataOffset else dataOffset -= count break default: throw new RuntimeException('Unknown action token', formatOffset) } formatOffset += tokenLen + 1 } return result as String[] } // utility method def cut2fmt(positions) { template = '' lastpos = 1 for (pos in positions) { template += 'A' + (pos - lastpos) + ' ' lastpos = pos } return template + 'A*' } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // use b if b is true, else c b = false; c = 'cat' assert (b ? b : c) == 'cat' b = true assert (b ? b : c) // can be simplified to 'b || c' if c is a boolean // strictly speaking, b doesn't have to be a boolean, // e.g. an empty list is coerced to boolean false b = [] assert (b ? b : c) == 'cat' // set x to y unless x is already true x = false; y = 'dog' if (!x) x = y assert x == 'dog' // can be simplified to 'x ||= y' if y is a boolean // x doesn't need to be a boolean, e.g. a non-empty // string is coerced to boolean true x = 'cat' if (!x) x = y assert x == 'cat' // JVM supplies user name // otherwise could use exec or built-in Ant features for reading environment vars assert System.getProperty('user.name') // test for nullity then for emptyness def setDefaultIfNullOrEmpty(startingPoint) { (!startingPoint || startingPoint.length() == 0) ? 'Greenwich' : startingPoint } assert setDefaultIfNullOrEmpty(null) == 'Greenwich' assert setDefaultIfNullOrEmpty('') == 'Greenwich' assert setDefaultIfNullOrEmpty('Something else') == 'Something else' //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- v1 = 'alpha'; v2 = 'omega' // this can done with explicit swapping via a temp variable // or in a slightly more interesting way with a closure swap = { temp = v1; v1 = v2; v2 = temp } swap() assert v1 == 'omega' && v2 == 'alpha' // a more generic swap() is also possible using Groovy's metaclass mechanisms // but is not idiomatic of Groovy usage //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // char and int are interchangable, apart from precision difference // char use 16 bits while int use 32, requiring a cast from int to char char ch = 'e' int num = ch // no problem ch = (char) num // needs an explicit cast s1 = "Number " + num + " is character " + (char) num assert s1 == 'Number 101 is character e' s2 = "Character " + ch + " is number " + (int) ch assert s2 == 'Character e is number 101' // easy conversion between char arrays, char lists and Strings char[] ascii = "sample".toCharArray() // {115, 97, 109, 112, 108, 101} assert new String(ascii) == "sample" assert new String([115, 97, 109, 112, 108, 101] as char[]) == "sample" // convert 'HAL' to 'IBM' (in increasing order of Grooviness) assert "HAL".toCharArray().collect{new String(it+1 as char[])}.join() == 'IBM' assert ("HAL" as String[]).collect{it.next()}.join() == 'IBM' assert "HAL".replaceAll('.', {it.next()}) == 'IBM' //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- string = "an apple a day" assert string[3..7].split('')[1..5] == ['a', 'p', 'p', 'l', 'e'] assert string.split('').toList().unique().sort().join() == ' adelnpy' //---------------------------------------------------------------------------------- // CheckSum.groovy: Compute 16-bit checksum of input file // Usage: groovy CheckSum <file> // script: checksum = 0 new File(args[0]).eachByte{ checksum += it } checksum %= (int) Math.pow(2, 16) - 1 println checksum //---------------------------------------------------------------------------------- // to run on its own source code: //=> % groovy CheckSum CheckSum.groovy //=> 9349 //---------------------------------------------------------------------------------- // Slowcat.groovy: Emulate a s l o w line printer // Usage: groovy Slowcat <file> <delay_millis_between_each_char> // script: delay = args[1].toInteger() new File(args[0]).eachByte{ print ((char) it); Thread.sleep(delay) } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- assert 'string'.reverse() == 'gnirts' string = 'Yoda said, "can you see this?"' revwords = string.split(' ').toList().reverse().join(' ') assert revwords == 'this?" see you "can said, Yoda' words = ['bob', 'alpha', 'rotator', 'omega', 'reviver'] long_palindromes = words.findAll{ w -> w == w.reverse() && w.size() > 5 } assert long_palindromes == ['rotator', 'reviver'] //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- s1 = 'abc\t def\tghi \n\tx' s2 = 'abc def ghi \n x' def expand(s) { s.split('\n').toList().collect{ line = it while (line.contains('\t')) { line = line.replaceAll(/([^\t]*)(\t)(.*)/){ all,pre,tab,suf -> pre + ' ' * (8 - pre.size() % 8) + suf } } return line }.join('\n') } def unexpand(s) { s.split('\n').toList().collect{ line = it for (i in line.size()-1..1) { if (i % 8 == 0) { prefix = line[0..<i] if (prefix.trim().size() != prefix.size()) { line = prefix.trim() + '\t' + line[i..-1] } } } return line }.join('\n') } assert expand(s1) == s2 assert unexpand(s2) == s1 //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- debt = 150 assert "You owe $debt to me" == 'You owe 150 to me' rows = 24; cols = 80 assert "I am $rows high and $cols wide" == 'I am 24 high and 80 wide' assert 'I am 17 years old'.replaceAll(/\d+/, {2*it.toInteger()}) == 'I am 34 years old' //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- assert "bo peep".toUpperCase() == 'BO PEEP' assert 'JOHN'.toLowerCase() == 'john' def capitalize(s) {s[0].toUpperCase() + (s.size()<2 ? '' : s[1..-1]?.toLowerCase())} assert capitalize('joHn') == 'John' s = "thIS is a loNG liNE".replaceAll(/\w+/){capitalize(it)} assert s == 'This Is A Long Line' s1 = 'JOhn'; s2 = 'joHN' assert s1.equalsIgnoreCase(s2) private Random rand def randomCase(char ch) { (rand.nextInt(100) < 20) ? Character.toLowerCase(ch) : ch } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- n = 10 assert "I have ${n+1} guanacos." == 'I have 11 guanacos.' assert "I have " + (n+1) + " guanacos." == 'I have 11 guanacos.' // sending templated email is solved in two parts: templating and sending // Part 1: creating an email template naughty = 'Mr Bad Credit' def get_manager_list(s) { 'The Big Boss' } msg = """ To: $naughty From: Your Bank Cc: ${ get_manager_list(naughty) } Date: ${ new Date() } Dear $naughty, Today, you bounced check number ${ 500 + new Random().nextInt(100) } to us. Your account is now closed. Sincerely, the management """ expected = ''' To: Mr Bad Credit From: Your Bank Cc: The Big Boss Date: XXX Dear Mr Bad Credit, Today, you bounced check number XXX to us. Your account is now closed. Sincerely, the management ''' sanitized = msg.replaceAll('(?m)^Date: (.*)$','Date: XXX') sanitized = sanitized.replaceAll(/(?m)check number (\d+) to/,'check number XXX to') assert sanitized == expected // note: Groovy also has several additional built-in templating facilities // Part 2: sending email // SendMail.groovy: Send email // Usage: groovy SendEmail <msgfile> // script: ant = new AntBuilder() ant.mail(from:'manager@grumpybank.com', tolist:'innocent@poorhouse.com', encoding:'plain', mailhost:'mail.someserver.com', subject:'Friendly Letter', message:'this is a test message') // Ant has many options for setting encoding, security, attachments, etc., see: // http://ant.apache.org/manual/CoreTasks/mail.html // Groovy could also use the Java Mail Api directly if required //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- def raw = ''' your text goes here ''' def expected = ''' your text goes here ''' assert raw.split('\n').toList().collect{ it.replaceAll(/^\s+/,'') }.join('\n') + '\n' == expected //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- input = '''Folding and splicing is the work of an editor, not a mere collection of silicon and mobile electrons!''' expected = '''Folding and splicing is the work of an editor, not a mere collection of silicon and mobile electrons!''' def wrap(text, maxSize) { all = [] line = '' text.eachMatch(/\S+/) { word = it[0] if (line.size() + 1 + word.size() > maxSize) { all += line line = word } else { line += (line == '' ? word : ' ' + word) } } all += line return all.join('\n') } assert wrap(input, 20) == expected //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- string = /Mom said, "Don't do that."/ // backslash special chars assert string.replaceAll(/['"]/){/\\/+it[0]} == /Mom said, \"Don\'t do that.\"/ //' // double special chars assert string.replaceAll(/['"]/){it[0]+it[0]} == /Mom said, ""Don''t do that.""/ //' //backslash quote all non-capital letters assert "DIR /?".replaceAll(/[^A-Z]/){/\\/+it[0]} == /DIR\ \/\?/ //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- assert ' x '.trim() == 'x' // print what's typed, but surrounded by >< symbols // script: new BufferedReader(new InputStreamReader(System.in)).eachLine{ println(">" + it.trim() + "<"); } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- pattern = /"([^\"\\]*(?:\\.[^\"\\]*)*)",?|([^,]+),?|,/ line = /XYZZY,"","O'Reilly, Inc","Wall, Larry","a \"glug\" bit,",5,"Error, Core Dumped"/ m = line =~ pattern expected = [/XYZZY/, '', /O'Reilly, Inc/, /Wall, Larry/, //' /a \"glug\" bit,/, /5/, /Error, Core Dumped/] for (i in 0..<m.size().toInteger()) assert expected[i] == (m[i][2] ? m[i][2] : m[i][1]) //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // A quick google search found several Java implementations. // As an example, how to use commons codec is shown below. // Just place the respective jar in your classpath. // Further details: http://jakarta.apache.org/commons/codec // require(groupId:'commons-codec', artifactId:'commons-codec', version:'1.3') soundex = new org.apache.commons.codec.language.Soundex() assert soundex.soundex('Smith') == soundex.soundex('Smyth') //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- input = '''I have analysed the new part. As long as you aren't worried about the colour, it is a dropin replacement.''' //' expected = '''I have analyzed the new part. As long as you aren't worried about the color, it is a drop-in replacement.''' //' translations = [colour:'color', analysed:'analyzed', dropin:'drop-in'] def fixstyle(s) { s.split('\n').toList().collect{ line = it translations.each{ key, value -> line = line.replaceAll(/(?<=\W)/ + key + /(?=\W)/, value) } return line }.join('\n') } assert fixstyle(input) == expected //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Solved in two parts: 'screenscrape' text stream and return stream from process // Part 1: text scraping input = ''' PID PPID PGID WINPID TTY UID STIME COMMAND 4636 1 4636 4636 con 1005 08:24:50 /usr/bin/bash 676 4636 676 788 con 1005 13:53:32 /usr/bin/ps ''' select1 = ''' PID PPID PGID WINPID TTY UID STIME COMMAND 676 4636 676 788 con 1005 13:53:32 /usr/bin/ps ''' select2 = ''' PID PPID PGID WINPID TTY UID STIME COMMAND 4636 1 4636 4636 con 1005 08:24:50 /usr/bin/bash ''' // line below must be configured for your unix - this one's cygwin format = cut2fmt([10, 18, 26, 37, 42, 47, 56]) def psgrep(s) { out = [] lines = input.split('\n').findAll{ it.size() } vars = unpack(format, lines[0]).toList().collect{ it.toLowerCase().trim() } out += lines[0] lines[1..-1].each{ values = unpack(format, it).toList().collect{ try { return it.toInteger() } catch(NumberFormatException e) { return it.trim() } } vars.eachWithIndex{ var, i -> binding.setVariable(var, values[i]) } if (new GroovyShell(binding).evaluate(s)) out += it } return '\n' + out.join('\n') + '\n' } assert psgrep('winpid < 800') == select1 assert psgrep('uid % 5 == 0 && command =~ /sh$/') == select2 // Part 2: obtaining text stream from process // unixScript: input = 'ps'.execute().text // cygwinScript: input = 'path_to_cygwin/bin/ps.exe'.execute().text // windowsScript: // can use something like sysinternal.com s pslist (with minor script tweaks) input = 'pslist.exe'.execute().text //---------------------------------------------------------------------------------- |