A function inversa $ .param () em JavaScript / jQuery

Dada a seguinte forma:

    

Eu posso usar a construção $.param( .. ) para serializar o formulário:

 $.param( $('form input') ) => foo=bar&hello=hello+world 

Como posso desserializar a String acima com JavaScript e obter um hash de volta?

Por exemplo,

 $.magicFunction("foo=bar&hello=hello+world") => {'foo' : 'bar', 'hello' : 'hello world'} 

Referência: jQuery.param( obj ) .

   

Você deve usar a function deparam do jQuery BBQ . É bem testado e documentado.

Esta é uma versão ligeiramente modificada de uma function que escrevi há um tempo atrás para fazer algo semelhante.

 var QueryStringToHash = function QueryStringToHash (query) { var query_string = {}; var vars = query.split("&"); for (var i=0;i 

Como sobre esta abordagem funcional curta?

 function parseParams(str) { return str.split('&').reduce(function (params, param) { var paramSplit = param.split('=').map(function (value) { return decodeURIComponent(value.replace(/\+/g, ' ')); }); params[paramSplit[0]] = paramSplit[1]; return params; }, {}); } 

Exemplo:

 parseParams("this=is&just=an&example") // Object {this: "is", just: "an", example: undefined} 

Minha resposta:

 function(query){ var setValue = function(root, path, value){ if(path.length > 1){ var dir = path.shift(); if( typeof root[dir] == 'undefined' ){ root[dir] = path[0] == '' ? [] : {}; } arguments.callee(root[dir], path, value); }else{ if( root instanceof Array ){ root.push(value); }else{ root[path] = value; } } }; var nvp = query.split('&'); var data = {}; for( var i = 0 ; i < nvp.length ; i++ ){ var pair = nvp[i].split('='); var name = decodeURIComponent(pair[0]); var value = decodeURIComponent(pair[1]); var path = name.match(/(^[^\[]+)(\[.*\]$)?/); var first = path[1]; if(path[2]){ //case of 'array[level1]' || 'array[level1][level2]' path = path[2].match(/(?=\[(.*)\]$)/)[1].split('][') }else{ //case of 'name' path = []; } path.unshift(first); setValue(data, path, value); } return data; } 

Eu estou usando a resposta de David Dorward e percebi que ela não se comporta como PHP ou Ruby on Rails como eles analisam os parâmetros:

1) uma variável é apenas uma matriz se termina com [] , como ?choice[]=1&choice[]=12 , não quando é ?a=1&a=2

2) quando existem vários parâmetros com o mesmo nome, os posteriores substituem os anteriores, como nos servidores PHP (Ruby on Rails mantém o primeiro e ignora os posteriores), como ?a=1&b=2&a=3

Então, modificando a versão de David, eu tenho:

 function QueryStringToHash(query) { if (query == '') return null; var hash = {}; var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); var k = decodeURIComponent(pair[0]); var v = decodeURIComponent(pair[1]); // If it is the first entry with this name if (typeof hash[k] === "undefined") { if (k.substr(k.length-2) != '[]') // not end with []. cannot use negative index as IE doesn't understand it hash[k] = v; else hash[k.substr(0, k.length-2)] = [v]; // If subsequent entry with this name and not array } else if (typeof hash[k] === "string") { hash[k] = v; // replace it // If subsequent entry with this name and is array } else { hash[k.substr(0, k.length-2)].push(v); } } return hash; }; 

que é testado de forma bastante completa.

Veja como você pode criar uma nova function jQuery:

 jQuery.unparam = function (value) { var // Object that holds names => values. params = {}, // Get query string pieces (separated by &) pieces = value.split('&'), // Temporary variables used in loop. pair, i, l; // Loop through query string pieces and assign params. for (i = 0, l = pieces.length; i < l; i++) { pair = pieces[i].split('=', 2); // Repeated parameters with the same name are overwritten. Parameters // with no value get set to boolean true. params[decodeURIComponent(pair[0])] = (pair.length == 2 ? decodeURIComponent(pair[1].replace(/\+/g, ' ')) : true); } return params; }; 

Graças a ele http://james.padolsey.com/javascript/parsing-urls-with-the-dom/

Muito fácil: D

 function params_unserialize(p){ var ret = {}, seg = p.replace(/^\?/,'').split('&'), len = seg.length, i = 0, s; for (;i 

Eu sei que isso é um tópico antigo, mas talvez ainda haja alguma relevância nisso?

Inspirado pela boa solução de Jacky Li, tentei uma ligeira variação com o objective de também poder cuidar de combinações arbitrárias de arrays e objects como input. Eu olhei como o PHP teria feito e tentei fazer algo “similar”. Aqui está o meu código:

 function getargs(str){ var ret={}; function build(urlnam,urlval,obj){ // extend the return object ... var i,k,o=obj, x, rx=/\[([^\]]*)\]/g, idx=[urlnam.replace(rx,'')]; while (x=rx.exec(urlnam)) idx.push(x[1]); while(true){ k=idx.shift(); if(k.trim()=='') {// key is empty: autoincremented index if (o.constructor.name=='Array') k=o.length; // for Array else if (o===obj ) {k=null} // for first level property name else {k=-1; // for Object for(i in o) if (+i>k) k=+i; k++; } } if(idx.length) { // set up an array if the next key (idx[0]) appears to be // numeric or empty, otherwise set up an object: if (o[k]==null || typeof o[k]!='object') o[k]=isNaN(idx[0])?{}:[]; o=o[k]; // move on to the next level } else { // OK, time to store the urlval in its chosen place ... // console.log('key',k,'val',urlval); o[k]=urlval===""?null:urlval; break; // ... and leave the while loop. } } return obj; } // ncnvt: is a flag that governs the conversion of // numeric strings into numbers var ncnvt=true,i,k,p,v,argarr=[], ar=(str||window.location.search.substring(1)).split("&"), l=ar.length; for (i=0;i"" && !isNaN(v)) v-=0; argarr.push([k,v]); // array: key-value-pairs of all arguments } for (i=0,l=argarr.length;i 

Se a function for chamada sem o argumento str ela assumirá window.location.search.slice(1) como input.

Alguns exemplos:

 ['a=1&a=2', // 1 'x[y][0][z][]=1', // 2 'hello=[%22world%22]&world=hello', // 3 'a=1&a=2&&b&c=3&d=&=e&', // 4 'fld[2][]=2&fld[][]=3&fld[3][]=4&fld[]=bb&fld[]=cc', // 5 $.param({a:[[1,2],[3,4],{aa:'one',bb:'two'},[5,6]]}), // 6 'a[]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13',// 7 'a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13'// 8 ].map(function(v){return JSON.stringify(getargs(v));}).join('\n') 

resulta em

 {"a":2} // 1 {"x":{"y":[{"z":[1]}]}} // 2 {"hello":"[\"world\"]","world":"hello"} // 3 {"a":2,"b":null,"c":3,"d":null,"null":"e"} // 4 = { a: 2, b: null, c: 3, d: null, null: "e" } {"fld":[null,null,[2],[3,4],"bb","cc"]} // 5 {"a":[[1,2],[3,4],{"aa":"one","bb":"two"},[5,6]]} // 6 {"a":["hi",2,null,[7,99],13]} // 7 {"a":{"0":2,"3":[7,99],"4":13,"x":"hi"}} // 8 

Considerando que a solução de Jacky Li produziria o recipiente externo para a object simples

 {a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output 

getargs() examina o primeiro índice dado para qualquer nível para determinar se este nível será um object (índice não numérico) ou um array (numérico ou vazio), resultando assim na saída como mostrado na lista acima (no. 6).

Se o object atual for uma matriz, então, null inseridos null s, sempre que necessário, para representar posições vazias. Os arrays são sempre numerados consecutivamente e baseados em 0).

Note que no exemplo não. 8 o "autoincrement" para índices vazios ainda funciona, apesar de estarmos lidando com um object agora e não com um array.

Até onde eu testei, meu getargs() se comporta de maneira muito idêntica ao ótimo plugin jQuery $.deparam() Chriss Roger mencionado na resposta aceita. A principal diferença é que o getargs é executado sem o jQuery e que ele faz incremento automático em objects, enquanto o $.deparam() não faz isso:

 JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a); 

resulta em

 {"3":["7","99"],"x":"hi","undefined":"13"} 

Em $.deparam() o índice [] é interpretado como um índice numérico undefined vez de um índice numérico autoincrementado.

Aqui está minha implementação JavaScript que eu uso em uma página JScript ASP Classic ( demo ) do lado do servidor:

 // Transforms a query string in the form x[y][0][z][]=1 into {x:{y:[{z:[1]}]}} function parseJQueryParams(p) { var params = {}; var pairs = p.split('&'); for (var i=0; i 

usa isto :

 // convert query string to json object var queryString = "cat=3&sort=1&page=1"; queryString .split("&") .forEach((item) => { const prop = item.split("="); filter[prop[0]] = prop[1]; }); console.log(queryString); 

Esta é minha versão no Coffeescript. Também funciona para URL como http://localhost:4567/index.html?hello=[%22world%22]&world=hello#/home

 getQueryString: (url)-> return null if typeof url isnt 'string' or url.indexOf("http") is -1 split = url.split "?" return null if split.length < 2 path = split[1] hash_pos = path.indexOf "#" path = path[0...hash_pos] if hash_pos isnt -1 data = path.split "&" ret = {} for d in data [name, val] = d.split "=" name = decodeURIComponent name val = decodeURIComponent val try ret[name] = JSON.parse val catch error ret[name] = val return ret 

Eu HttpUtility.ParseQueryString essa solução, que se comporta como a function .Net HttpUtility.ParseQueryString .

No resultado, os parâmetros da string de consulta são armazenados em propriedades como listas de valores, de modo que qsObj["param"] será o mesmo que chamar GetValues("param") em .Net.

Espero que você goste. JQuery não é obrigatório.

 var parseQueryString = function (querystring) { var qsObj = new Object(); if (querystring) { var parts = querystring.replace(/\?/, "").split("&"); var up = function (k, v) { var a = qsObj[k]; if (typeof a == "undefined") { qsObj[k] = [v]; } else if (a instanceof Array) { a.push(v); } }; for (var i in parts) { var part = parts[i]; var kv = part.split('='); if (kv.length == 1) { var v = decodeURIComponent(kv[0] || ""); up(null, v); } else if (kv.length > 1) { var k = decodeURIComponent(kv[0] || ""); var v = decodeURIComponent(kv[1] || ""); up(k, v); } } } return qsObj; }; 

Aqui está como usá-lo:

 var qsObj = parseQueryString("a=1&a=2&&b&c=3&d=&=e&"); 

Para visualizar o resultado no console, digite juste em:

 JSON.stringify(qsObj) 

Saída:

 "{"a":["1","2"],"null":["","b",""],"c":["3"],"d":[""],"":["e"]}" 

Há um belo one-liner no CSS-Tricks (fonte original de Nicholas Ortenzio ):

 function getQueryParameters(str) { return (str || document.location.search).replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0]; } 

A parte realmente inteligente é como ele usa o object anônimo da function anônima, adicionando um par chave / valor para cada uma das consultas na string. Dito isso, há espaço para melhorias. Eu modifiquei um pouco abaixo, com as seguintes alterações:

  1. Adicionado manipulação de strings vazias e inputs não-string.

  2. Manipular strings codificadas por URI ( %40 -> @ , etc).

  3. Removido o uso padrão de document.location.search quando a input estava vazia.

  4. Mudou o nome, tornou mais legível, acrescentou comentários.

 function deparam(str) { // Uses an empty 'this' to build up the results internally function splitQuery(query) { query = query.split('=').map(decodeURIComponent); this[query[0]] = query[1]; return this; } // Catch bad input if (!str || !(typeof str === 'string' || str instanceof String)) return {}; // Split the string, run splitQuery on each piece, and return 'this' var queries = str.replace(/(^\?)/,'').split('&'); return queries.map(splitQuery.bind({}))[0]; } 

Aqui está um simples e compacto se você quiser apenas obter rapidamente os parâmetros de uma solicitação GET:

 function httpGet() { var a={},b,i,q=location.search.replace(/^\?/,"").split(/\&/); for(i in q) if(q[i]) {b=q[i].split("=");if(b[0]) a[b[0]]= decodeURIComponent(b[1]).replace(/\+/g," ");} return a; } 

Converte

 something?aa=1&bb=2&cc=3 

em um object como

 {aa:1,bb:2,cc:3} 

Cria uma representação serializada de uma matriz ou object (pode ser usado como uma string de consulta de URL para solicitações AJAX).

  
output:firstname=vishal&lastname=pambhar

respostas poderiam usar um pouco de elegância jQuery :

 (function($) { var re = /([^&=]+)=?([^&]*)/g; var decodeRE = /\+/g; // Regex for replacing addition symbol with a space var decode = function (str) {return decodeURIComponent( str.replace(decodeRE, " ") );}; $.parseParams = function(query) { var params = {}, e; while ( e = re.exec(query) ) { var k = decode( e[1] ), v = decode( e[2] ); if (k.substring(k.length - 2) === '[]') { k = k.substring(0, k.length - 2); (params[k] || (params[k] = [])).push(v); } else params[k] = v; } return params; }; })(jQuery); 

garfo em https://gist.github.com/956897

Você pode usar a function .serializeArray() ( Link ) do próprio jQuery. Esta function retorna uma matriz de pares de valores-chave. Exemplo de resultado:

 [ { name: "id", value: "1" }, { name: "version", value: "100" } ]