[groovy-user] parsing strings into maps

6 views
Skip to first unread message

Kallin Nagelberg

unread,
Jan 13, 2008, 3:46:01 PM1/13/08
to us...@groovy.codehaus.org
Does anyone know of a way to parse a string into a map?
IE, the string is "[key1:value1,key2:value2]" . I am trying to write a utility where users can specify an arbitrary list of optional parameters which will be converted into a map anyways, so I figured it would be simplest to just use the groovy map syntax. Unfortunately def mymap = "[key1:value1,key2:value2]" cannot be used as a map. Any ideas?

Thanks,
Kallin Nagelberg


Guillaume Laforge

unread,
Jan 13, 2008, 3:49:12 PM1/13/08
to us...@groovy.codehaus.org

Inside a script, you can do:
def mymap = evaluate("[key1:value1,key2:value2]")

And in a class, you can instantiate a GroovyShell and do this:
def mymap = new GroovyShell().evaluate("[key1:value1,key2:value2]")

--
Guillaume Laforge
Groovy Project Manager
G2One, Inc. Vice-President Technology
http://www.g2one.com

---------------------------------------------------------------------
To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Kallin Nagelberg

unread,
Jan 13, 2008, 4:01:24 PM1/13/08
to us...@groovy.codehaus.org
Thanks for the quick response!

I've tried implementing it exactly as you put it, but I'm getting the following exception:

Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.485 sec <<< FAILURE!
testValidCommands(CommandRunnerTest)  Time elapsed: 0.437 sec  <<< ERROR!
groovy.lang.MissingPropertyException: No such property: value1 for class: Script1
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java :888)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:2077)
    at groovy.lang.GroovyObjectSupport.getProperty(GroovyObjectSupport.java:65)
    at groovy.lang.Script.getProperty(Script.java:85)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getGroovyObjectProperty(ScriptBytecodeAdapter.java:560)
    at Script1.run(Script1.groovy)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:484)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:459)
    at gjdk.groovy.lang.GroovyShell_GroovyReflector.invoke(Unknown Source)
    at groovy.lang.MetaMethod.invoke(MetaMethod.java:115)
    at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke (MetaClassHelper.java:713)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:560)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:450)
    at org.codehaus.groovy.runtime.Invoker.invokeMethod (Invoker.java:131)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:111)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:187)

Guillaume Laforge

unread,
Jan 13, 2008, 4:07:32 PM1/13/08
to us...@groovy.codehaus.org
Of course, you have to replace the dummy values with real values!

Paul King

unread,
Jan 13, 2008, 4:11:38 PM1/13/08
to us...@groovy.codehaus.org

You would need to have quotes around the values. A regex would probably
do that fairly easily if you didn't want the quotes in your original.

Paul.

> <mailto:glaf...@gmail.com>> wrote:
>
> On Jan 13, 2008 9:46 PM, Kallin Nagelberg

Kallin Nagelberg

unread,
Jan 13, 2008, 4:12:49 PM1/13/08
to us...@groovy.codehaus.org
Ahh, I'm working with strictly string values here so I thought perhaps I could avoid quoting them. When I changed it to:

def mymap = new GroovyShell().evaluate("[\"key1\":\"value1\",\"key2\":\"value2\"]")
it works great !


On Jan 13, 2008 4:07 PM, Guillaume Laforge <glaf...@gmail.com> wrote:
Of course, you have to replace the dummy values with real values!

On Jan 13, 2008 10:01 PM, Kallin Nagelberg <kallin.n...@gmail.com > wrote:
> Thanks for the quick response!
>
> I've tried implementing it exactly as you put it, but I'm getting the
> following exception:
>
> Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.485 sec
> <<< FAILURE!
> testValidCommands(CommandRunnerTest)  Time elapsed: 0.437 sec  <<< ERROR!
> groovy.lang.MissingPropertyException: No such property: value1 for class:
> Script1
>     at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java :888)
>     at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:2077)
>     at
> groovy.lang.GroovyObjectSupport.getProperty (GroovyObjectSupport.java:65)

>     at groovy.lang.Script.getProperty(Script.java:85)
>      at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getGroovyObjectProperty(ScriptBytecodeAdapter.java:560)
>     at Script1.run(Script1.groovy)
>     at groovy.lang.GroovyShell.evaluate(GroovyShell.java:484)
>     at groovy.lang.GroovyShell.evaluate(GroovyShell.java:459)
>     at gjdk.groovy.lang.GroovyShell_GroovyReflector.invoke (Unknown Source)

>     at groovy.lang.MetaMethod.invoke(MetaMethod.java:115)
>     at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke
> (MetaClassHelper.java:713)
>     at groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:560)

>     at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:450)
>     at org.codehaus.groovy.runtime.Invoker.invokeMethod (Invoker.java:131)
>     at
> org.codehaus.groovy.runtime.InvokerHelper.invokeMethod (InvokerHelper.java:111)

Guillaume Laforge

unread,
Jan 13, 2008, 4:17:54 PM1/13/08
to us...@groovy.codehaus.org
You can also use single quotes if you wish.

def mymap = new GroovyShell().evaluate("[key1: 'value1', key2: 'value2']")

Keys don't need to be quoted.

Paul King

unread,
Jan 13, 2008, 4:18:29 PM1/13/08
to us...@groovy.codehaus.org

Single quotes could be used too.

Kallin Nagelberg wrote:
> Ahh, I'm working with strictly string values here so I thought perhaps I
> could avoid quoting them. When I changed it to:
>
> def mymap = new
> GroovyShell().evaluate("[\"key1\":\"value1\",\"key2\":\"value2\"]")
> it works great !
>
>
> On Jan 13, 2008 4:07 PM, Guillaume Laforge <glaf...@gmail.com

> <mailto:glaf...@gmail.com>> wrote:
>
> Of course, you have to replace the dummy values with real values!
>
> On Jan 13, 2008 10:01 PM, Kallin Nagelberg

> <mailto:glaf...@gmail.com>> wrote:
> > >
> > >
> > >
> > >
> > >
> > >
> > > On Jan 13, 2008 9:46 PM, Kallin Nagelberg <

> kallin.n...@gmail.com <mailto:kallin.n...@gmail.com>>

Kallin Nagelberg

unread,
Jan 13, 2008, 4:21:47 PM1/13/08
to us...@groovy.codehaus.org
Seeing as all the keys and values will always be strings it would be nice to avoid the need to quote everything. I could write something to replace every key:value with "key":"value". Looks like I'll get to play with groovy's regex support for the first time :) (I'm a groovy neophyte if you couldn't tell).

Kallin Nagelberg

unread,
Jan 13, 2008, 6:51:16 PM1/13/08
to us...@groovy.codehaus.org
I wrote a little static method to perform the necessary quoting. I replace the keys and values seperately, and it works, but I would really like to know of a 'groovier' way to do this. I would love to see how some experts would change this method.

static String quoteMap(String stringmap) {
        assert stringmap

        def quotedStringMap
        def word = /\w+/

        def keyPattern = /($word):/
        String keysReplaced = stringmap.replaceAll (keyPattern) { all, foundWord ->
            /"$foundWord":/
        }

        def valuePattern = /:($word)/
        String valuesReplaced = keysReplaced.replaceAll(valuePattern) { all, foundWord ->
            /:"$foundWord"/
        }

        quotedStringMap = valuesReplaced

        println "quoted string map is $quotedStringMap"

        return quotedStringMap

Gerrit Geens

unread,
Jan 14, 2008, 2:32:03 AM1/14/08
to us...@groovy.codehaus.org
You could also do it like this:

stringMap = '[key1:val1,key2:val2,key3:val3]'
replacedStringMap = str.replaceAll( /(\w+):(\w+)/, { all, key, val -> "'$key':'$val'" })

Kallin Nagelberg

unread,
Jan 14, 2008, 7:32:16 AM1/14/08
to us...@groovy.codehaus.org
Hehe yeah I thought that initially but it fails the test of nested maps:

verb noun [key1:value1,key2:value2,key3:[nestedkey1:nestedvalue1,nestedkey2:nestedvalue2]]

Thorsten Kamann

unread,
Jan 14, 2008, 7:40:24 AM1/14/08
to us...@groovy.codehaus.org
Kallin Nagelberg schrieb:

> Hehe yeah I thought that initially but it fails the test of nested maps:
>
> verb noun
> [key1:value1,key2:value2,key3:[nestedkey1:nestedvalue1,nestedkey2:nestedvalue2]]

Hmm. This should work:

println
Eval.me('[key1:"value1",key2:"value2",key3:[nestedkey1:"nestedvalue1",nestedkey2:"nestedvalue2"]]')

I have sorrounded the values with doublequotes, because of they are not
properties but Strings...
And I am not sure how the performance of Eval.me is...

Thorsten

--
Thorsten Kamann
Software-Architect, Consultant, Coaching
Germany, NRW

thorste...@googlemail.com
http://www.thorsten-kamann.de/
callto://thorque

Fornax-Platform - Platform for developing MDSD-related Tools and components
http://www.fornax-platform.org/

Jürgen Hermann

unread,
Jan 14, 2008, 7:51:51 AM1/14/08
to us...@groovy.codehaus.org
> From: Kallin Nagelberg [mailto:kallin.n...@gmail.com]
> Hehe yeah I thought that initially but it fails the test of
> nested maps:
>
> verb noun
> [key1:value1,key2:value2,key3:[nestedkey1:nestedvalue1,nestedk
> ey2:nestedvalue2]]

Instead of using regex, you can also set a delegate that resolves the identifiers to strings. In the end, the whole thing is a micro-DSL anyway.

Reply all
Reply to author
Forward
0 new messages