问题描述
我目前正在尝试将 URL 查询字符串转换为 JavaScript 对象,但进展并不顺利。我已经环顾 Stack Overflow 寻找可能的解决方案,但还没有完全找到我想要的。这是查询字符串:
"class%5Blocation_id%5D=122&student%5Bgender%5D=&student%5Bpicture%5D=&class%5Bquestions%5D%5B2775%5D%5Banswers%5D%5B%5D=Black+canary&ids%5B%5D=32&class%5Bquestions%5D%5B2775%5D%5Banswer%5D=&class%5Bquestions%5D%5B2776%5D%5Banswers%5D%5B%5D=Blue+Whistle&class%5Bquestions%5D%5B2776%5D%5Banswer%5D=&class%5Bdescription%5D="
我正在寻找这样的东西:
{
class: {
description: '',location_id: '122',questions: {
2275: {
answer: '',answers: ['Black canary']
},2276: {
answer: '',answers: ['Blue Whistle']
}
}
},ids: ['32']
student: {
gender: '',picture: ''
}
}
我尝试使用名为 query-string 的库,但结果如下:
{
'class[description]': '','class[location_id]': '122','class[questions][2775][answer]': '','class[questions][2775][answers][]': 'Black canary','class[questions][2776][answer]': '','class[questions][2776][answers][]': 'Blue Whistle','ids[]': '32','student[gender]': '','student[picture]': ''
}
我尝试使用我发现的两个实现here:
function form2Json(str) {
"use strict";
var obj,i,pt,keys,j,ev;
if (typeof form2Json.br !== 'function') {
form2Json.br = function (repl) {
if (repl.indexOf(']') !== -1) {
return repl.replace(/\](.+?)(,|$)/g,function ($1,$2,$3) {
return form2Json.br($2 + '}' + $3);
});
}
return repl;
};
}
str = '{"' + (str.indexOf('%') !== -1 ? decodeURI(str) : str) + '"}';
obj = str.replace(/\=/g,'":"').replace(/&/g,'","').replace(/\[/g,'":{"');
obj = JSON.parse(obj.replace(/\](.+?)(,$3) { return form2Json.br($2 + '}' + $3); }));
pt = ('&' + str).replace(/(\[|\]|\=)/g,'"$1"').replace(/\]"+/g,']').replace(/&([^\[\=]+?)(\[|\=)/g,'"&["$1]$2');
pt = (pt + '"').replace(/^"&/,'').split('&');
for (i = 0; i < pt.length; i++) {
ev = obj;
keys = pt[i].match(/(?!:(\["))([^"]+?)(?=("\]))/g);
for (j = 0; j < keys.length; j++) {
if (!ev.hasOwnProperty(keys[j])) {
if (keys.length > (j + 1)) {
ev[keys[j]] = {};
}
else {
ev[keys[j]] = pt[i].split('=')[1].replace(/"/g,'');
break;
}
}
ev = ev[keys[j]];
}
}
return obj;
}
但结果是这样的:
{
class: {
description: "",location_id: "122"
},questions:{
2775: {answers: "Black+canary",answer: ""}
2776: {answers: "Blue+Whistle",answer: ""}
},ids: {
"": "32"
},student: {
gender: ""
picture: ""
}
}
ids
成为对象而不是数组,answers
成为字符串。
我能得到的最接近它的是使用这个:
function form2Json(str) {
"use strict";
var pairs = str.split('&'),result = {};
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('='),key = decodeURIComponent(pair[0]),value = decodeURIComponent(pair[1]),isArray = /\[\]$/.test(key),dictMatch = key.match(/^(.+)\[([^\]]+)\]$/);
if (dictMatch) {
key = dictMatch[1];
var subkey = dictMatch[2];
result[key] = result[key] || {};
result[key][subkey] = value;
} else if (isArray) {
key = key.substring(0,key.length - 2);
result[key] = result[key] || [];
result[key].push(value);
} else {
result[key] = value;
}
}
return result;
}
结果如下:
{
class: {location_id: "122",description: ""},class[questions][2775]: {answer: ""},class[questions][2775][answers]: ["Black+canary"],class[questions][2776]: {answer: ""},class[questions][2776][answers]: ["Blue+Whistle"],ids: ["32"],student: {gender: "",picture: ""}
}
...最多只有一级关联,并且 ids
的数组被正确分配为数组。我怎样才能做到这一点?
解决方法
您可以使用URLSearchParams
:
script | Traceback (most recent call last):
script | File "/test_db/testDb.py",line 10,in <module>
script | TestDb().run()
script | File "/test_db/testDb.py",line 5,in run
script | conn = pymysql.connect(host='mysql',port=3306,database='sta_db',user='root',password='Alphashadow1381')
script | File "/usr/local/lib/python3.9/site-packages/pymysql/__init__.py",line 94,in Connect
script | return Connection(*args,**kwargs)
script | File "/usr/local/lib/python3.9/site-packages/pymysql/connections.py",line 327,in __init__
script | self.connect()
script | File "/usr/local/lib/python3.9/site-packages/pymysql/connections.py",line 619,in connect
script | raise exc
script | pymysql.err.OperationalError: (2003,"Can't connect to MySQL server on 'mysql' ([Errno 111] Connection refused)")
对于旧版浏览器
这是 EcmaScript 2015 兼容的:
function form2Object(str) {
let result = {};
for (let [path,value] of new URLSearchParams(str).entries()) {
let keys = path.match(/[^[\]]+/g);
let prop = keys.pop();
let acc = result;
for (let key of keys) acc = (acc[key] = acc[key] || {});
acc[prop] = path.endsWith("[]")
? (acc[prop] || []).concat(value)
: value;
}
return result;
}
// Demo
let str = "class%5Blocation_id%5D=122&student%5Bgender%5D=&student%5Bpicture%5D=&class%5Bquestions%5D%5B2775%5D%5Banswers%5D%5B%5D=Black+canary&ids%5B%5D=32&class%5Bquestions%5D%5B2775%5D%5Banswer%5D=&class%5Bquestions%5D%5B2776%5D%5Banswers%5D%5B%5D=Blue+Whistle&class%5Bquestions%5D%5B2776%5D%5Banswer%5D=&class%5Bdescription%5D=";
console.log(form2Object(str));