作为一个以groovy开头的tcl开发人员,我对groovy中的列表和地图支持感到有些惊讶。也许我在这里遗漏了一些东西。
我习惯在tcl中即时转换字符串,列表和数组/映射。在tcl中,类似
"['a':2,'b':4]".each {key, value -> println key + " " + value}
是可能的,在groovy中,每个命令都会遍历字符串的每个字符。
这可能是一个很大的问题,我可以很容易地使用像split或tokenize命令这样的东西,但是因为序列化的列表或地图不只是“a:2,b:4”,所以有点难度解析。
似乎griffon开发人员使用stringToMap库(http://code.google.com/p/stringtomap/),但该示例也无法处理序列化地图。
所以现在我的问题是:在groovy中解析地图或列表的最佳方法是什么?
干杯, 拉尔夫
PS:这是一个时髦的问题,但我用grails标记了它,因为我需要grails的这个功能,我想通过URL传递地图更新:这对我来说仍然是一个悬而未决的问题...所以这里有一些针对同样问题的人的更新:
.toString()
会导致某些内容无法在所有情况下转回地图,但.inspect()
会为您提供一个字符串被评估回地图!.encodeAsJSON()
和JSON.parse(String)
- 两者都很好用,但我还没有检查解析器将使用JSON函数做什么(可能存在安全问题)答案 0 :(得分:22)
您可能希望使用评估尝试一些场景,它可能会满足您的需求。
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"
答案 1 :(得分:11)
不完全是原生的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 :(得分: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's why we need one loop more
config.each { _,v ->
v.each {key, value -> println key + " " + value}
}
答案 3 :(得分:1)
如果您不想使用evaluate(),请改为:
def stringMap = "['a':2,'b':4]"
stringMap = stringMap.replaceAll('\\[|\\]','')
def newMap = [:]
stringMap.tokenize(',').each {
kvTuple = it.tokenize(':')
newMap[kvTuple[0]] = kvTuple[1]
}
println newMap
答案 4 :(得分:0)
我希望有帮助:
foo= "['a':2,'b':4]"
Map mapResult=[:]
mapResult += foo.replaceAll('\\[|\\]', '').split(',').collectEntries { entry ->
def pair = entry.split(':')
[(pair.first().trim()): pair.last().trim()]
}