Groovy: нет ли stringToMap из коробки?
как разработчик tcl, начиная с groovy, я немного удивлен поддержкой списка и карт в groovy. Может быть, мне что-то не хватает.
Я использую для преобразования между строками, списками и массивами/картами в tcl на лету. В tcl что-то вроде
"['a':2,'b':4]".each {key, value -> println key + " " + value}
где, как и в groovy, каждая команда проходит через каждый символ строки.
Это была бы большая проблема, я мог бы легко использовать что-то вроде команды split или tokenize, но поскольку сериализованный список или карта не просто "a: 2, b: 4", это немного сложнее для синтаксического анализа.
Кажется, разработчики гриффона используют библиотеку stringToMap (http://code.google.com/p/stringtomap/), но пример не может справиться с сериализованными картами.
Итак, мой вопрос: какой лучший способ разобрать карту или список в groovy?
Cheers,
Ralf
PS: это вопрос groovy, но я привязал его к grails, потому что мне нужна эта функция для grails, где я хотел бы передавать карты через URL
Обновление:. Это все еще открытый вопрос для меня... так вот некоторые обновления для тех, у кого такая же проблема:
- когда вы превращаете карту в строку, a
.toString()
приведет к чему-то, что во всех случаях не может быть возвращено в карту, но .inspect()
предоставит вам строку, которая может быть оценена обратно карту!
- в Grails существует
.encodeAsJSON()
и JSON.parse(String)
- оба работают отлично, но я еще не проверил, что будет делать синтаксический анализатор с функциями JSON (возможная проблема безопасности).
Ответы
Ответ 1
Не совсем native groovy, но полезен для сериализации в JSON:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
def map = ['a':2,'b':4 ]
def s = new JsonBuilder(map).toString()
println s
assert map == new JsonSlurper().parseText(s)
с мета-программированием:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
Map.metaClass.toJson = { new JsonBuilder(delegate).toString() }
String.metaClass.toMap = { new JsonSlurper().parseText(delegate) }
def map = ['a':2,'b':4 ]
assert map.toJson() == '{"a":2,"b":4}'
assert map.toJson().toMap() == map
К сожалению, невозможно переопределить метод toString()...
Ответ 2
Возможно, вы захотите попробовать несколько сценариев, используя оцените, он может делать то, что вы ищете.
def stringMap = "['a':2,'b':4]"
def map = evaluate(stringMap)
assert map.a == 2
assert map.b == 4
def stringMapNested = "['foo':'bar', baz:['alpha':'beta']]"
def map2 = evaluate(stringMapNested)
assert map2.foo == "bar"
assert map2.baz.alpha == "beta"
Ответ 3
Я думаю, вы ищете комбинацию ConfigObject и ConfigSlurper. Что-то вроде этого сделало бы трюк.
def foo = new ConfigObject()
foo.bar = [ 'a' : 2, 'b' : 4 ]
// we need to serialize it
new File( 'serialized.groovy' ).withWriter{ writer ->
foo.writeTo( writer )
}
def config = new ConfigSlurper().parse(new File('serialized.groovy').toURL())
// highest level structure is a map ["bar":...], that why we need one loop more
config.each { _,v ->
v.each {key, value -> println key + " " + value}
}
Ответ 4
Если вы не хотите использовать функцию оценки(), то вместо этого:
def stringMap = "['a':2,'b':4]"
stringMap = stringMap.replaceAll('\\[|\\]','')
def newMap = [:]
stringMap.tokenize(',').each {
kvTuple = it.tokenize(':')
newMap[kvTuple[0]] = kvTuple[1]
}
println newMap
Ответ 5
Я надеюсь, что это поможет:
foo= "['a':2,'b':4]"
Map mapResult=[:]
mapResult += foo.replaceAll('\\[|\\]', '').split(',').collectEntries { entry ->
def pair = entry.split(':')
[(pair.first().trim()): pair.last().trim()]
}