Last active
December 11, 2015 05:28
-
-
Save alisey/4552101 to your computer and use it in GitHub Desktop.
Parsing URL query string in JavaScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Examples: | |
// parseQueryString('a=1&a=2') => {a: '2'} | |
// parseQueryString('a=1', true) => {a: ['1']} | |
// parseQueryString('a=1&a=2', true) => {a: ['1', '2']} | |
// parseQueryString('a[][]=1&a[][]=2', true) => {'a[][]': ['1', '2']} | |
// parseQueryString('?a;b#c') => {'?a': '', 'b#c': ''} | |
function parseQueryString(query, groupByName) { | |
var parsed, hasOwn, pairs, pair, name, value; | |
if (typeof query != 'string') { | |
throw 'Invalid input'; | |
} | |
parsed = {}; | |
hasOwn = parsed.hasOwnProperty; | |
query = query.replace(/\+/g, ' '); | |
pairs = query.split(/[&;]/); | |
for (var i = 0; i < pairs.length; i++) { | |
pair = pairs[i].match(/^([^=]*)=?(.*)/); | |
if (pair[1]) { | |
try { | |
name = decodeURIComponent(pair[1]); | |
value = decodeURIComponent(pair[2]); | |
} catch(e) { | |
throw 'Invaid %-encoded sequence'; | |
} | |
if (!groupByName) { | |
parsed[name] = value; | |
} else if (hasOwn.call(parsed, name)) { | |
parsed[name].push(value); | |
} else { | |
parsed[name] = [value]; | |
} | |
} | |
} | |
return parsed; | |
} | |
// qUnit Tests | |
test("parseQueryString keyval format", function() { | |
deepEqual(parseQueryString('a=1'), {'a': '1'}); | |
deepEqual(parseQueryString('a='), {'a': ''}); | |
deepEqual(parseQueryString('a'), {'a': ''}); | |
deepEqual(parseQueryString('='), {}); | |
deepEqual(parseQueryString(''), {}); | |
deepEqual(parseQueryString('=1'), {}); | |
deepEqual(parseQueryString('==='), {}); | |
deepEqual(parseQueryString('a==1'), {'a': '=1'}); | |
deepEqual(parseQueryString('a%3D1'), {'a=1' : ''}); | |
}); | |
test("parseQueryString pair separator", function() { | |
deepEqual(parseQueryString('a=1&b=1'), {a: '1', b: '1'}); | |
// http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2 | |
deepEqual(parseQueryString('a=1;b=1'), {a: '1', b: '1'}); | |
}); | |
test("parseQueryString special characters", function() { | |
deepEqual(parseQueryString('&&&=1'), {}); | |
deepEqual(parseQueryString('???=1'), {'???': '1'}); | |
deepEqual(parseQueryString('###=1'), {'###': '1'}); | |
deepEqual(parseQueryString('a+%2B+b=1'), {'a + b': '1'}); | |
deepEqual(parseQueryString("\u0020\r\n\t=1"), {"\u0020\r\n\t": '1'}); | |
deepEqual(parseQueryString('%C2%A9=%C2%A9'), {'©': '©'}); | |
deepEqual(parseQueryString('привет=пока'), {'привет': 'пока'}); | |
}); | |
test("parseQueryString lists and duplicates", function() { | |
deepEqual(parseQueryString('a=1&a=2'), {'a': '2'}); | |
deepEqual(parseQueryString('a=1', true), {'a': ['1']}); | |
deepEqual(parseQueryString('a=1&a=2', true), {'a': ['1', '2']}); | |
deepEqual(parseQueryString('a[]b=1', true), {'a[]b': ['1']}); | |
deepEqual(parseQueryString('a[=1', true), {'a[': ['1']}); | |
deepEqual(parseQueryString('a[]=1&a[]=1', true), {'a[]': ['1', '1']}); | |
deepEqual(parseQueryString('a[][]=1&a[][]=1', true), {'a[][]': ['1', '1']}); | |
deepEqual(parseQueryString('a[8][0]=1&a[8][1]=1', true), | |
{'a[8][0]': ['1'], 'a[8][1]': ['1']}); | |
}); | |
test("parseQueryString built-in property override", function() { | |
deepEqual(parseQueryString('hasOwnProperty=1'), {'hasOwnProperty': '1'}); | |
deepEqual(parseQueryString('toString=1'), {'toString': '1'}); | |
}); | |
test("parseQueryString exceptions", function() { | |
throws(function() { parseQueryString('%C2%79'); }, | |
'Invalid UTF-8 sequence throws an exception'); | |
throws(function() { parseQueryString(null); }, | |
'Input data is a string'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment