Подтвердить что ты не робот

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

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

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

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

Ответ 1

Не совсем native 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

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

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"

Ответ 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 why we need one loop more
config.each { _,v ->
    v.each {key, value -> println key + " " + value}
}

Ответ 4

Если вы не хотите использовать функцию оценки(), то вместо этого:

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

Ответ 5

Я надеюсь, что это поможет:

    foo= "['a':2,'b':4]"
    Map mapResult=[:]
    mapResult += foo.replaceAll('\\[|\\]', '').split(',').collectEntries { entry ->
        def pair = entry.split(':')
        [(pair.first().trim()): pair.last().trim()]
       }