Single Speechmarks not added to numbers - groovy

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

Related

Is there any way to get the output of Spark's Dataset.show() method as a string?

The Spark Dataset.show() method is useful for seeing the contents of a dataset, particularly for debugging (it prints out a nicely-formatted table). As far as I can tell, it only prints to the console, but it would be useful to be able to get this as a string. For example, it would be nice to be able to write it to a log, or see it as the result of an expression when debugging with, say, IntelliJ.
Is there any way to get the output of Dataset.show() as a string?
The corresponding method behind show isn't visible from outside the sql package. I've taken the corresponding method and changed it such that a dataframe can be passed as parameter (code taken from Dataset.scala) :
def showString(df:DataFrame,_numRows: Int = 20, truncate: Int = 20): String = {
val numRows = _numRows.max(0)
val takeResult = df.take(numRows + 1)
val hasMoreData = takeResult.length > numRows
val data = takeResult.take(numRows)
// For array values, replace Seq and Array with square brackets
// For cells that are beyond `truncate` characters, replace it with the
// first `truncate-3` and "..."
val rows: Seq[Seq[String]] = df.schema.fieldNames.toSeq +: data.map { row =>
row.toSeq.map { cell =>
val str = cell match {
case null => "null"
case binary: Array[Byte] => binary.map("%02X".format(_)).mkString("[", " ", "]")
case array: Array[_] => array.mkString("[", ", ", "]")
case seq: Seq[_] => seq.mkString("[", ", ", "]")
case _ => cell.toString
}
if (truncate > 0 && str.length > truncate) {
// do not show ellipses for strings shorter than 4 characters.
if (truncate < 4) str.substring(0, truncate)
else str.substring(0, truncate - 3) + "..."
} else {
str
}
}: Seq[String]
}
val sb = new StringBuilder
val numCols = df.schema.fieldNames.length
// Initialise the width of each column to a minimum value of '3'
val colWidths = Array.fill(numCols)(3)
// Compute the width of each column
for (row <- rows) {
for ((cell, i) <- row.zipWithIndex) {
colWidths(i) = math.max(colWidths(i), cell.length)
}
}
// Create SeparateLine
val sep: String = colWidths.map("-" * _).addString(sb, "+", "+", "+\n").toString()
// column names
rows.head.zipWithIndex.map { case (cell, i) =>
if (truncate > 0) {
StringUtils.leftPad(cell, colWidths(i))
} else {
StringUtils.rightPad(cell, colWidths(i))
}
}.addString(sb, "|", "|", "|\n")
sb.append(sep)
// data
rows.tail.map {
_.zipWithIndex.map { case (cell, i) =>
if (truncate > 0) {
StringUtils.leftPad(cell.toString, colWidths(i))
} else {
StringUtils.rightPad(cell.toString, colWidths(i))
}
}.addString(sb, "|", "|", "|\n")
}
sb.append(sep)
// For Data that has more than "numRows" records
if (hasMoreData) {
val rowsString = if (numRows == 1) "row" else "rows"
sb.append(s"only showing top $numRows $rowsString\n")
}
sb.toString()
}

Groovy String to CSV

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.

Divide Swift String into groups of 3 symbols

I'm making a formatter for currency string, for example I have Int:
let a: Int = 10
let b: Int = 10000
let c: Int = 10000000
I want them to be formatted like:
let a1:String = "10"
let b1:String = "10 000"
let c1:String = "10 000 000"
So I need funtion (or extension) in Swift as elegant, as you can suggest =) You have a Int as input parameter and you should output it as a String with " "(space symbol) every 3 symbols from right to left.
this may help you :
func formatNumberString(number : String?) -> String?
{
//"10 000 000 M"
// 01234567890123 -> 2,6,10
if (number?.isEmpty == true || number?.length <= 2) {
return number
}
var i : Int = 0
var newNumber : String = ""
for character in (number?.characters)! {
if ((i == 2 || i == 6 || i == 10) && character != " ")
{
newNumber = newNumber + " "
}
i++
}
return newNumber
}
You should user NSNumberFormatter to format your number:
func numberToCurrency(number: Int) -> String {
let formatter: NSNumberFormatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.positiveSuffix = " M"
formatter.currencySymbol = ""
formatter.maximumFractionDigits = 0
formatter.currencyGroupingSeparator = " "
formatter.usesGroupingSeparator = true
return formatter.stringFromNumber(number)!
}
print(numberToCurrency(1000)) will print 1 000 M. If you don't want to show M character, just set formatter.positiveSuffix = ""
You can use this as extension and just call if input is string
let requiredN = "10000000".convertToFormat()
this is the extension for string
extension String
{
func convertToFormat() -> String
{
return (NSNumberFormatter.localizedStringFromNumber(Int(self)!, numberStyle: NSNumberFormatterStyle.DecimalStyle) as String).stringByReplacingOccurrencesOfString(",", withString: " ")
}
}
If input value is Int call
let requiredN = 10000000.convertToFormat()
and extension for Int
extension Int
{
func convertToFormat() -> String
{
return (NSNumberFormatter.localizedStringFromNumber(self, numberStyle: NSNumberFormatterStyle.DecimalStyle) as String).stringByReplacingOccurrencesOfString(",", withString: " ")
}
}

changing map values in groovy doesn't work

I am using Groovy version 2.1.0. I am trying to read values from a map and update another map.
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
def key2 = "key2"
a.key2 = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is ::
But if the map 'a' doesn't contain empty string as values, then it works fine as expected.
a = ["key1":"7" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
a."key2" = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is :10:
I want to update the empty map with values, like in the first scenario. Where am I getting it wrong.
Thanks in advance.
You need to change:
if( i.key in a)
a.(i.key) = i.value
To:
if( i.key in a.keySet())
a.(i.key) = i.value
As Opal says, it's the if that's causing difficulties...
if( i.key in a)
Will fail if the key is not in the map, OR the value equates to Groovy False
You could do:
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
a = (a+b).findAll { k, v -> k in a.keySet() }
def key2 = "key2"
a[ key2 ] = "value2"
println a.key2
println "value returned is : $a.key1 :"
(be careful, your key2 bit wasn't doing what I believe you expected (it worked as your key2 var name was the same as its value)

How I can find the contents of inner nesting?

Lets say I have a string like this :
string = [+++[>>[--]]]abced
Now I want a someway to return a list that has: [[--],[>>],[+++]]. That is the contents of the deepest [ nesting followed by other nesting. I came up with this solution like this :
def string = "[+++[>>[--]]]"
loop = []
temp = []
string.each {
bool = false
if(it == "["){
temp = []
bool = true
}
else if( it != "]")
temp << it
if(bool)
loop << temp
}
println loop.reverse()
But this indeed takes the abced string after the last ] and put into the result!. But what I want is only [[--],[>>],[+++]]
Are there any groovy way of solving this?
You can use this, if you wouldn't mind using recursion
def sub(s , list){
if(!s.contains('[') && !s.contains('['))
return list
def clipped = s.substring(s.lastIndexOf('[')+1, s.indexOf(']'))
list.add(clipped)
s = s - "[$clipped]"
sub(s , list)
}
Calling
sub('''[+++[>>[--]]]abced''' , [])
returns a list of all subportions enclosed between braces.
['--', '>>', '+++']
If your brackets are symmetrical, you could just introduce a counter variable that holds the depth of the bracket nesting. Only depth levels above 0 are allowed in the output:
def string = "[+++[>>[--]]]abc"
loop = []
temp = []
depth = 0;
string.each {
bool = false
if(it == "["){
temp = []
bool = true
depth++;
}
else if (it == "]"){
depth--;
}
else if (depth > 0){
temp << it
}
if(bool){
loop << temp
}
}
println loop.reverse()
class Main {
private static final def pattern = ~/([^\[]*)\[(.+?)\][^\]]*/
static void main(String[] args) {
def string = "[+++[>>[--]]]abced"
def result = match(string)
println result
}
static def match(String val) {
def matcher = pattern.matcher(val);
if (matcher.matches()) {
return matcher.group(1) ? match(matcher.group(2)) + matcher.group(1) : match(matcher.group(2))
}
[val]
}
}
System.out
[--, >>, +++]
The capturing of the first group in the regex pattern could probably be improved. Right now the first group is any character that is not [ and if there are nothing in front of the first [ then the first group will contain an empty string.

Resources