Groovy: нет ли в списке готовой таблицы? - PullRequest
22 голосов
/ 06 февраля 2010

Как разработчик 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: это отличный вопрос, но я пометил его граалями, потому что мне нужна эта функциональность для граалей, где я хотел бы передавать карты через URL

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

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

Ответы [ 4 ]

22 голосов
/ 06 февраля 2010

Возможно, вы захотите попробовать несколько ваших сценариев, используя оцените , он может сделать то, что вы ищете.

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"
11 голосов
/ 08 июля 2014

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

3 голосов
/ 06 февраля 2010

Я думаю, вы ищете комбинацию 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}
}
1 голос
/ 08 октября 2013

Если вы не хотите использовать define (), вместо этого выполните:

def stringMap = "['a':2,'b':4]"
stringMap = stringMap.replaceAll('\\[|\\]','')
def newMap = [:]
stringMap.tokenize(',').each {
kvTuple = it.tokenize(':')
newMap[kvTuple[0]] = kvTuple[1]
}
println newMap
...