29

作为一个从 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 传递地图

更新:这对我来说仍然是一个悬而未决的问题......所以这里有一些更新给那些有同样问题的人:

  • 当您将 Map 转换为 String 时, a.toString()将导致在所有情况下都无法转换回 map 的结果,但是 an.inspect()将为您提供一个 String ,可以将其评估回​​ map !
  • 在 Grails 中,有一个.encodeAsJSON()JSON.parse(String)- 两者都很好用,但我还没有检查解析器将如何处理 JSON 函数(可能的安全问题)
4

5 回答 5

30

您可能想使用evaluate尝试一些场景,它可能会满足您的需求。

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"
于 2010-02-06T17:14:14.407 回答
19

不完全是原生的 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() 方法...

于 2014-07-08T15:26:56.410 回答
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}
}
于 2010-02-06T09:53:27.610 回答
1

如果您不想使用评估(),请改为:

def stringMap = "['a':2,'b':4]"
stringMap = stringMap.replaceAll('\\[|\\]','')
def newMap = [:]
stringMap.tokenize(',').each {
kvTuple = it.tokenize(':')
newMap[kvTuple[0]] = kvTuple[1]
}
println newMap
于 2013-10-08T19:16:04.283 回答
1

我希望这会有所帮助:

    foo= "['a':2,'b':4]"
    Map mapResult=[:]
    mapResult += foo.replaceAll('\\[|\\]', '').split(',').collectEntries { entry ->
        def pair = entry.split(':')
        [(pair.first().trim()): pair.last().trim()]
       }
于 2019-10-08T19:17:21.323 回答