views:

53

answers:

4

Say, we have a query string that looks like this:

"param1:'test1' && param2:'test2'"

I would like to turn it into an object map, like this:

{param:test1, param2:test2}

How could that be done? This seems like a very common use case.

+3  A: 

As long as it's in that format, i.e. only has string values (and the strings don't contain " && " or colons), you can easily parse it:

var params = theString.split(' && ');
var map = {};
for (var i = 0; i < params.length; i++) {
  var parts = params[i].split(':');
  map[parts[0]] = parts[1].substr(1, parts[1].length - 2);
}

Note that the strings are of course still strings: { param: 'test1', param2: 'test2' }

Guffa
+7  A: 

I usually use the "search and don't replace" method:

var ret = {},
    str = "param1:'test1' && param2:'test2'";

str.replace(/(\b[^:]+):'([^']+)'/g, function ($0, param, value) {
    ret[param] = value;
});

JSON.stringify(ret);
// -> { "param1": "test1", "param2":"test2" }

Example: http://jsfiddle.net/bcJ9s/

Andy E
+1: This is a little more robust than my suggestion. Still could be improved; if there is a space between the identifier and the colon, it's included in the identifier. :)
Guffa
@Guffa: thanks :-)
Andy E
The important thing, here, is whether you can predict the format of the 'strings' up front, in order to make the regexp as simple as possible. This will help with maintenance, in the future, but should probably be well documented somewhere, so that it's clear what the assumptions are.
belugabob
+1  A: 

Use string processing (As mentioned by @Guffa, it will fail if strings themselves contained && or :):

var str="param1:'test1' && param2:'test2'";
var map={};
var pairs=str.split('&&');
for(i=0, total=pairs.length; i<total; i++) {
  var pair=pairs[i].trim().split(':');
  map[pair[0]]=pair[1].substr(1, pair[1].length-2);
}

Note: trim() is not available on old browsers, you need to add this bit of code before the one above [src]:

if (!String.prototype.trim) {
    String.prototype.trim = function () {
        return this.replace(/^\s*(\S*(?:\s+\S+)*)\s*$/, "$1");
    };
}
aularon
Guffa
You are right, I thought of that but read what you said above your answer so I thought somebody else referred to this I don't have to, but I proabably should edit referring to this too, thanks.
aularon
+1  A: 

Use the string.split function to break the string into the parts that you need - something like this...

var input = "param1:'test1' && param2:'test2'";
var entries = input.split(" && ");
var map = {};
var pattern = /'/g;
for(var i=0; i < entries.length; i++){
    var tokens = entries[i].split[":"];
    map[tokens[0]] = tokens[1].replace(pattern, "");
}
belugabob
It's rather satisfying to see that other people have arrived at almost exactly the same solution - need to spend a while understanding the answer provided by Andy E, as I've never seen string.replac used with a function as the second parameter. Maybe Andy E could expand his answer for the benefit of others like me.
belugabob
Guffa
@belugabob: it's very much like a regex *exec()*, except there's no loop and you're naming the sub-captures in their own private closure. That's why I linked to article where John Resig coined the term and explained the method :-)
Andy E
@Guffa - very true, which is why the answer provided by Andy E is interesting.
belugabob
@Andy E - didn't spot the link. Thanks for pointing it out - using a function that returns a string, instead of a string is easy to understand, but I didn't know that the function has certain aspects of the regexp search passed to it. As usual, Mr Resig knows best. :-)
belugabob