I have a string input of the structure like:
[{name=John, dob=1970-07-27 00:00:00.0, score=81},
{name=Jane, dob=1970-07-28 00:00:00.0, score=77}]
I am trying to convert it to a CSV output. So expected output:
"name", "dob", "score"
"John", "1970-07-27 00:00:00.0", 81
"Jane", "1970-07-28 00:00:00.0", 77
So far I have tried something like
def js = "[{name=John, dob=1970-07-27 00:00:00.0, score=81}, {name=Jane, dob=1970-07-28 00:00:00.0, score=77}]"
def js = new JsonSlurper().parseText(s)
def columns = js*.keySet().flatten().unique()
def encode = { e -> e == null ? '' : e instanceof String ? /"$e"/ : "$e" }
// Print all the column names
println columns.collect { c -> encode( c ) }.join( ',' )
// Then create all the rows
println data.infile.collect { row ->
// A row at a time
columns.collect { colName -> encode( row[ colName ] ) }.join( ',' )
}.join( '\n' )
This fails with groovy.json.JsonException: expecting '}' or ',' but got current char 'n'
Defining var js without quotes fails with expecting '}', found ','
Thanks in advance
I wrote this simple parser which will go splitting lines. If your input changes (i.e., comma or = is used in any other place), you will need a more complex parser:
input = '''[{name=John, dob=1970-07-27 00:00:00.0, score=81},
{name=Jane, dob=1970-07-28 00:00:00.0, score=77},
{name=Test, dob=1980-01-01 00:00:00.0, score=90}]'''
maps = (input =~ /\{(.*)\}/)
.collect {
it[1]
.split(', ')
.collectEntries { entry ->
entry.split '=' with {
[it.first(), it.last()]
}
}
}
assert maps == [
[name:'John', dob:'1970-07-27 00:00:00.0', score:'81'],
[name:'Jane', dob:'1970-07-28 00:00:00.0', score:'77'],
[name:'Test', dob:'1980-01-01 00:00:00.0', score:'90']
]
You can try this code snippet
import groovy.json.JsonSlurper
def s = '[{"name":"John", "dob":"1970-07-27 00:00:00.0", "score":81},{"name":"Jane", "dob":"1970-07-28 00:00:00.0", "score":77}]'
def js = new JsonSlurper().parseText(s)
def columns = js*.keySet().flatten().unique()
def encode = { e -> e == null ? '' : e instanceof String ? /"$e"/ : "$e" }
println columns.collect { c -> encode(c) }.join(',')
js.each {
println it.values().join(",")
}
I used Groovy JsonSlurper to convert String to Map, For this you need to give proper json String.
Related
I have a string containing a version number like major.minor.patch.build but I only want to keep major.minor.patch where each number can have 1-3 digits.
How can I do this in groovy?
Examples for a result:
1.20.30.44 -> 1.20.30
or
1.21.1.1 -> 1.21.1
This will work for provided examples.
def majorMinorPatchBuild = '1.20.30.44'
def majorMinorPatch
if (majorMinorPatchBuild.toList().count('.') < 3) {
majorMinorPatch = majorMinorPatchBuild
} else {
majorMinorPatch = majorMinorPatchBuild.split('\\.')[0..-2].join('.')
}
assert majorMinorPatch == '1.20.30'
Note, you'll have to implement some error handling if the input data will have some format deviations.
Test on more data:
[
'1.2.3',
'1.2.3.4',
'11.22.33.44',
'111.222.333.444'
].each {
def majorMinorPatchBuild = it
def majorMinorPatch
if (majorMinorPatchBuild.toList().count('.') < 3) {
majorMinorPatch = majorMinorPatchBuild
} else {
majorMinorPatch = majorMinorPatchBuild.split('\\.')[0..-2].join('.')
}
println("major.minor.patch: '$it' -> '$majorMinorPatch'")
}
Output:
major.minor.patch: '1.2.3' -> '1.2.3'
major.minor.patch: '1.2.3.4' -> '1.2.3'
major.minor.patch: '11.22.33.44' -> '11.22.33'
major.minor.patch: '111.222.333.444' -> '111.222.333'
That should be essentially one-liners in Groovy. To start with 2:
String listBased = '1.20.30.44'.split( /\./ ).take 3 join '.'
String regexBased = '1.20.30.44'.replaceFirst( /(.+)\.[^.]+/, '$1' )
assert listBased == '1.20.30'
assert regexBased == '1.20.30'
This expression returns the substring of an versionString before the last dot - and so results exactly what you have specified in your question:
versionString = '1.20.30.44'
println versionString[0..versionString.lastIndexOf('.')-1]
// => 1.20.30
I have a version like below and I want to add zero (0) in versionB after 2 decimal. How can I achieve this in groovy?
versionA=1.12.14
versionB=1.11
Expected OutPut:-
versionA=1.12.14
VersionB=1.11.0
Solution
The term you are are looking for is Semantic Versioning ( semver ). This is not the prettiest solution but it will work
//def semver = "1"
def semver = "1.13"
def split = semver.split("\\.");
if(split.size() == 1) {
semver+=".0.0"
} else if(split.size()==2) {
semver+=".0"
}
println semver
In your example you have the variables typed as numbers but they must be strings
A generic variant for version strings of variable lengths:
String getFormattedVersion( String raw, int maxPositions = 3 ){
def parts = raw.split( /\./ )
(0..<maxPositions).collect{ it < parts.size() ? parts[ it ] : '0' }.join '.'
}
assert '1.2.3' == getFormattedVersion( '1.2.3' )
assert '1.2.0' == getFormattedVersion( '1.2' )
assert '1.0.0' == getFormattedVersion( '1' )
assert '1.2.3.0.0' == getFormattedVersion( '1.2.3', 5 )
I have the below Code which works, except for if there is a number in the text field so a single speech mark does not get added around say 1 but would be around one.
As an aside I don't want speechmarks on the first column (the ID value)
SEP = ", "
QUOTE = "\'"
NEWLINE = System.getProperty("line.separator")
KEYWORDS_LOWERCASE = com.intellij.database.util.DbSqlUtil.areKeywordsLowerCase(PROJECT)
KW_INSERT_INTO = KEYWORDS_LOWERCASE ? "insert into " : "INSERT INTO "
KW_VALUES = KEYWORDS_LOWERCASE ? ") values (" : ") VALUES ("
KW_NULL = KEYWORDS_LOWERCASE ? "null" : "NULL"
def record(columns, dataRow) {
OUT.append(KW_INSERT_INTO)
if (TABLE == null) OUT.append("MY_TABLE")
else OUT.append(TABLE.getParent().getName()).append(".").append(TABLE.getName())
OUT.append(" (")
columns.eachWithIndex { column, idx ->
OUT.append(column.name()).append(idx != columns.size() - 1 ? SEP : "")
}
OUT.append(KW_VALUES)
columns.eachWithIndex { column, idx ->
def value = dataRow.value(column)
def stringValue = value != null ? FORMATTER.format(dataRow, column) : KW_NULL
if (DIALECT.getDbms().isMysql())
stringValue = stringValue.replace("\\", "\\\\")
OUT.append(skipQuote ? "": QUOTE).append(stringValue.replace(QUOTE, QUOTE + QUOTE))
.append(skipQuote ? "": QUOTE).append(idx != columns.size() - 1 ? SEP : "")
}
OUT.append(");").append(NEWLINE)
}
ROWS.each { row -> record(COLUMNS, row) }
Not 100% sure what and why you are trying to achieve, but I would write down something like that in idiomatic groovy:
LinkedHashMap.metaClass.value = { delegate.get it } // mock value()
TABLE = [ parent:[ name:'OTHER_TABLE' ] ] // fake TABLE
KEYWORDS_LOWERCASE = true // false
KW_INSERT_INTO = 'INSERT INTO'
KW_VALUES = 'VALUES'
if( KEYWORDS_LOWERCASE ){
KW_INSERT_INTO = KW_INSERT_INTO.toLowerCase()
KW_VALUES = KW_VALUES.toLowerCase()
}
COLUMNS = [ 'a', 'nullllll', 'c', 'numberString' ]
String record(columns, dataRow) {
List values = columns.collect{
def v = dataRow.value it
switch( v ){
case Number:
case ~/\d+/: return v
case String: return "'$v'"
default: return 'null'
}
}
"$KW_INSERT_INTO ${TABLE?.parent?.name ?: 'MY_TABLE'} (${columns.join( ', ' )}) $KW_VALUES (${values.join( ', ' )});\n"
}
String res = record( COLUMNS, [ a:'aa', c:42, numberString:'84' ] )
assert res == "insert into OTHER_TABLE (a, nullllll, c, numberString) values ('aa', null, 42, 84);\n"
In switch statement the values are getting formatted.
You can try out yourself at https://groovyconsole.appspot.com/script/5151418931478528
Here is the code i am trying to get working
def expr = ''
List params = []
params << 'filter-name'
params << 'servlet-name'
params << 'url-pattern'
params.each{expr = expr+ "it.'${it}'.text().trim()#"}
expr = expr.substring(0, expr.length()-1)
consNodes.each{
println "data is:$"{expr}"
println "actual : ${it.'filter-name'.text().trim()}#${it.'servlet-name'.text().trim()}#${it.'url-pattern'.text().trim()}"
}
in the above result comes like
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : presenceLogoutFilter##/adfAuthentication/*
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : remoteApplication##/rr/*
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : ServletADFContextFilter#GetHandler#
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : ServletADFContextFilter##/PresenceServlet/*
So, as you can see that my constructed expression is not able to evaluate further. Any advise on how to make it work?
The problem is that you're creating a GString like this: "it.'${it}'.text().trim()#", but then you're converting it into a String when you concatenate it: expr + "it.'${it}'.text().trim()#". Once you turn a GString into a String it no longer evaluates expressions. But even if you address that it won't solve your problem because GStrings do not evaluate like you think they do. The best way to explain it is with an example:
import org.codehaus.groovy.runtime.GStringImpl
// What you're doing
def a = 'John'
def b = 'Hello, $a'
def c = "${a}"
assert b == 'Hello, $a'
// What the compiler is doing (ignoring the variable name changes)
def aa = 'John'
def bb = 'Hello, $a'
def cc = new GStringImpl([] as Object[], ['Hello, $a'] as String[])
assert cc == 'Hello, $a'
// What you want the compiler to do, but it will not.
def aaa = 'John'
def bbb = 'Hello, $a'
def ccc = new GStringImpl(['John'] as Object[], ['Hello, '] as String[])
assert ccc == 'Hello, John'
If you really want to, you can build the GStrings manually, but that will be very difficult. And you'd end up depending on a class which is not guaranteed to remain backward-compatible between Groovy releases.
Here's what you can do instead:
def params = []
params << 'filter-name'
params << 'servlet-name'
params << 'url-pattern'
def evaluators = params.collect {
{ attr, node -> node[attr]?.text()?.trim() ?: '' }.curry(it)
}
consNodes.each { node ->
println evaluators.collect { c -> c(node) }.join('#')
}
The output looks like this:
presenceLogoutFilter##/adfAuthentication/*
remoteApplication##/rr/*
ServletADFContextFilter#GetHandler#
ServletADFContextFilter##/PresenceServlet/*
Instead of a single large expression you and up with a list of closures, each responsible for evaluating a node attribute. Then, you can join the results with '#'s.
I have a problem to get last two digit from a string.
example :
String texter = "5793231309"
how to get '09' ?
so when Iprintln "texter : "+texter.
It will be Groovy<<09
I try split but it not successful ?
Use this to split your first String:
static main(args) {
String texter = "5793231309"
String texter2 = texter[-2..-1]
println(texter2)
}
Here's a one liner that's also a safe alternative:
assert "5793231309".reverse().take(2).reverse() == "09"
In groovy you can substring via negative indices.
String last2 = texter[-2..-1] // Last 2 symbols
Its an analogue of substring, and it uses Ranges.
http://groovy.codehaus.org/Collections see 'Slicing with the subscript operator'
Inspired by tim_yates:
It may be safer to use some function, to extract last n characters, as tim suggested. But I think his solution, with regexp is a big overhead, and may be hard to understand by novices.
There is an easier and faster way to do this, using size() check, and then range substring:
def lastN(String input, int n){
return n > input?.size() ? null : n ? input[-n..-1] : ''
}
assert lastN("Hello", 2) == 'lo'
assert lastN("Hello", 3) == 'llo'
assert lastN("Hello", 0) == ''
assert lastN("Hello", 13) == null
assert lastN(null, 3) == null
Be careful though, if your unit is less than 2 characters long, s[ -2..-1 ] will fail.
Might be better to do:
String lastN( String input, int n ) {
input == null ?
null :
( input =~ /^.+(\S{$n})$/ ).with { m -> m.matches() ?
m[ 0 ][ 1 ] :
null }
}
assert lastN( "5793231309", 2 ) == '09'
assert lastN( "5793231309", 3 ) == '309'
assert lastN( "5793231309", 0 ) == ''
assert lastN( '', 2 ) == null
assert lastN( null, 2 ) == null
Or:
String lastN( String input, int n ) {
if( input == null || input.length() < n ) null
else if( n == 0 ) ''
else input[ -n..-1 ]
}
assert lastN( "5793231309", 2 ) == '09'
assert lastN( "5793231309", 3 ) == '309'
assert lastN( "5793231309", 0 ) == ''
assert lastN( '', 2 ) == null
assert lastN( null, 2 ) == null
The most readable solution is probably just to drop() all but the last two characters:
def texter = "5793231309"
println texter.drop(texter.size() - 2) //result: "09"
Or as a reusable closure:
def lastTwo = { it.drop(it.size() - 2) }
println lastTwo("ABC") //result: "BC"
println lastTwo("AB") //result: "AB"
println lastTwo("A") //result: "A" (no exception thrown)
println lastTwo("") //result: "" (no exception thrown)
Fiddle with the code:
https://groovyconsole.appspot.com/script/5768158526832640
More examples of Groovy goodness:
http://mrhaki.blogspot.com/2011/09/groovy-goodness-take-and-drop-items.html
Another safe alternative using size() and substring() methods:
s?.size() < 2 ? s : s.substring(s.size() - 2)
Note the above takes care of nulls and strings that are less than two characters long.
In Java use
String texter = "5793231309";
String val=texter.substring(texter.length()-2,texter.length());
System.out.println("val-->"+val);
In Groovy you don’t need the above stuff just,
String value= texter[-2..-1]