Groovy:是不是有开箱即用的stringToMap?

时间:2010-02-06 09:03:01

标签: string grails groovy map params

作为一个以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()会为您提供一个字符串被评估回地图!
  • 在Grails中,
  • 有一个.encodeAsJSON()JSON.parse(String) - 两者都很好用,但我还没有检查解析器将使用JSON函数做什么(可能存在安全问题)

5 个答案:

答案 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()]
       }