Groovy: разве нет stringToMap из коробки?

как разработчик tcl, начиная с groovy, я немного удивлен поддержкой списка и карты в 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?

Ура, Ральф!--6-->

PS: Это классный вопрос, но у меня есть пометил его граалями, потому что мне нужна эта функциональность для граалей, где я хотел бы передать карты через URL

обновление: это все еще открытый вопрос для меня... так вот некоторые обновления для тех, кто имеет ту же проблему:

  • когда вы превращаете карту в строку, a .toString() выльется в то, что не может быть превращен обратно в карту во всех случаях, но .inspect() даст вам строку, которая может быть оценена обратно карта!
  • в Grails, есть .encodeAsJSON() и JSON.parse(String) - оба отлично работают, но я еще не проверил, что парсер будет делать с функциями JSON (возможная проблема безопасности)

4 ответов


не совсем родной 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 ()...


вы можете попробовать несколько сценариев с помощью оценить он может делать то, что вы ищете.

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"

Я думаю, что вы ищете комбинацию 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}
}

Если вы не хотите использовать 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