แปลงสตริงวัตถุเป็น JSON


165

ฉันจะแปลงสตริงที่อธิบายวัตถุเป็นสตริง JSON โดยใช้ JavaScript (หรือ jQuery) ได้อย่างไร

เช่น: แปลงสิ่งนี้ ( ไม่ใช่สตริง JSON ที่ถูกต้อง):

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"

เป็นนี้

str = '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

ฉันชอบที่จะหลีกเลี่ยงการใช้eval()ถ้าเป็นไปได้


ทำไมสตริงของคุณไม่ถูกต้อง JSON ตั้งแต่แรก? คุณเป็นอย่างไร
Rocket Hazmat

2
สตริงถูกเก็บในdata-attrubute เช่นนี้<div data-object="{hello:'world'}"></div>และฉันไม่ต้องการใช้อัญประกาศเดี่ยวใน HTML (ดังนั้นจึงอาจไม่น่าเชื่อถือ)
snorpey

5
@snorpey: <div data-object='{"hello":"world"}'></div>เป็น HTML ที่ถูกต้อง 100% (เครื่องหมายคำพูดเดี่ยวเกี่ยวข้องกับการไว้วางใจหรือไม่?) ถ้าคุณทำแบบนี้คุณก็JSON.parseทำได้และมันก็ใช้ได้ดี หมายเหตุ:ปุ่มจะต้องมีการเสนอราคาเช่นกัน
Rocket Hazmat

@Rocket ขอบคุณสำหรับความพยายามของคุณ! ฉันแค่ต้องการหาวิธีแก้ไขการใช้เครื่องหมายคำพูดเดี่ยวใน HTML (แม้ว่ามันจะถูกต้อง 100%) และสัญกรณ์ JSON
snorpey

@snorpey: วิธีที่พวกเขาหลีกเลี่ยงไม่ให้ใส่ JSON ในแอตทริบิวต์ HTML ในตอนแรก ผมคิดว่าคุณสามารถใช้คำพูดคู่และหลบหนีคนใน <div data-object="{\"hello\":\"world\"}"></div>JSON หากคุณไม่ต้องการใช้ JSON ที่ถูกต้องในแอททริบิวคุณจะต้องจัดรูปแบบของคุณเองและแยกวิเคราะห์ด้วยตัวคุณเอง
Rocket Hazmat

คำตอบ:


181

ถ้าสตริงจากแหล่งที่เชื่อถือได้คุณสามารถใช้evalแล้วJSON.stringifyผลที่ตามมา แบบนี้:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));

โปรดทราบว่าเมื่อคุณevalวัตถุตามตัวอักษรมันจะต้องถูกห่อในวงเล็บมิฉะนั้นวงเล็บปีกกาจะแยกเป็นบล็อกแทนวัตถุ

ผมยังเห็นด้วยกับความคิดเห็นภายใต้คำถามที่ว่ามันจะดีกว่ามากที่จะเพียงแค่เข้ารหัสวัตถุ JSON ที่ถูกต้องที่จะเริ่มต้นด้วยและหลีกเลี่ยงที่จะแยกเข้ารหัสแล้วคงจะแยกมันอีกครั้ง HTML รองรับแอตทริบิวต์ที่ยกมาเดี่ยว (ต้องแน่ใจว่า HTML เข้ารหัสคำพูดใด ๆ ภายในสตริง)


สิ่งนี้ไม่สมเหตุสมผลถ้าสตริงมาจากแหล่งที่เชื่อถือได้ทำไมเราแปลงมันแทนเราทำให้มันเป็น json ที่ถูกต้อง
allenhwkim

2
@allenhwkim แนวคิดคือการแปลงจาก JSON ที่ไม่ถูกต้องเป็น JSON ที่ถูกต้องดังนั้นจึงevalแปลงสตริงเป็นวัตถุ JavaScript (ซึ่งใช้งานได้ตราบใดที่สตริงนั้นแสดงถึง JavaScript ที่ถูกต้องแม้ว่าจะไม่ใช่ JSON ที่ถูกต้องก็ตาม) จากนั้นJSON.stringifyแปลงจากวัตถุกลับไปเป็นสตริง JSON ที่ถูกต้อง การโทรevalเป็นอันตรายหากสตริงไม่ได้มาจากแหล่งที่เชื่อถือได้เพราะสามารถเรียกใช้ JavaScript ใด ๆ ซึ่งเปิดโอกาสในการโจมตีสคริปต์ข้ามไซต์
Matthew Crumley

2
eval จะยังคงทำสิ่งที่ไม่ดีในกรณีนี้หากมีการสร้างสตริงตัวอย่างเช่น: var str = "(function () {console.log (\" bad \ ")}) ()";
Rondo

การใช้ eval () จะใช้รหัส JS มันสามารถถูกทำร้ายได้ง่าย
FisNaN

@allenhwkim: เราไม่เคยเชื่อถือแหล่งข้อมูลใด ๆ เชื่อมั่นในไอทีหมายถึงการตรวจสอบตรวจสอบและตรวจสอบอีกครั้ง
Laszlo Varga

110

สตริงของคุณไม่ถูกต้อง JSON ดังนั้นJSON.parse(หรือ jQuery's $.parseJSON) จะไม่ทำงาน

วิธีหนึ่งที่จะใช้evalในการ "แยกวิเคราะห์" JSON "ไม่ถูกต้อง" และจากนั้นstringifyเป็น "แปลง" เป็น JSON ที่ถูกต้อง

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"
str = JSON.stringify(eval('('+str+')'));

ฉันแนะนำแทนที่จะพยายาม "แก้ไข" JSON ที่ไม่ถูกต้องของคุณคุณเริ่มต้นด้วย JSON ที่ถูกต้องตั้งแต่แรก มันจะstrถูกสร้างขึ้นอย่างไรควรได้รับการแก้ไขก่อนที่มันจะถูกสร้างขึ้นไม่ใช่หลังจากนั้น

แก้ไข : คุณพูดว่า (ในความคิดเห็น) สตริงนี้จะถูกเก็บไว้ในแอตทริบิวต์ข้อมูล:

<div data-object="{hello:'world'}"></div>

ฉันขอแนะนำให้คุณแก้ไขที่นี่ดังนั้นมันอาจจะเป็นJSON.parsed ก่อนอื่นทั้งคีย์และค่าจะต้องมีเครื่องหมายคำพูดคู่ ควรมีลักษณะ (แอตทริบิวต์ที่ยกมาเดี่ยวใน HTML ถูกต้อง):

<div data-object='{"hello":"world"}'></div>

ตอนนี้คุณสามารถใช้JSON.parse(หรือ jQuery's $.parseJSON)

var str = '{"hello":"world"}';
var obj = JSON.parse(str);

49

jQuery.parseJSON

str = jQuery.parseJSON(str)

แก้ไข สิ่งนี้จัดให้คุณมีสตริง JSON ที่ถูกต้อง


1
ฉันจริงเห็นคำถามเป็นวิธีการแปลงสตริง JSON ไปยังวัตถุ
Farmor

43

ใช้รหัสอย่างง่ายในลิงค์ด้านล่าง:

http://msdn.microsoft.com/es-es/library/ie/cc836466%28v=vs.94%29.aspx

var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);

และย้อนกลับ

var str = JSON.stringify(arr);

การแปลง jsontext เป็นวัตถุ String ผ่าน String ใหม่ (jsontext) น่าจะดียิ่งขึ้นเพื่อความปลอดภัยของประเภท
วิเคราะห์ฟัซซี

@fuzzyanalysis: ไม่ไม่ควรใช้แผ่นปิดแบบดั้งเดิม
Ry-

1
JSON.parse () ควรเป็นคำตอบที่ได้รับการยอมรับที่นี่ตามที่ระบุโดย @LouiseMcMahon
พิกเซล 67

24

ฉันหวังว่าฟังก์ชันเล็ก ๆ นี้จะแปลงสตริง JSON ที่ไม่ถูกต้องให้เป็นสตริงที่ถูกต้อง

function JSONize(str) {
  return str
    // wrap keys without quote with valid double quote
    .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})    
    // replacing single quote wrapped ones to double quote 
    .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})         
}

ผลลัพธ์

var invalidJSON = "{ hello: 'world',foo:1,  bar  : '2', foo1: 1, _bar : 2, $2: 3, 'xxx': 5, \"fuz\": 4, places: ['Africa', 'America', 'Asia', 'Australia'] }"
JSON.parse(invalidJSON) 
//Result: Uncaught SyntaxError: Unexpected token h VM1058:2
JSON.parse(JSONize(invalidJSON)) 
//Result: Object {hello: "world", foo: 1, bar: "2", foo1: 1, _bar: 2…}

เรากำลังพยายามยกเลิกการประเมิน b โดยใช้ JSON.parse รหัสของเราและนี่เป็นวิธีที่ดี เรายังคงต้องจัดการกับการเปลี่ยนด้วยมืออย่างสม่ำเสมอ แต่อย่างน้อยสิ่งนี้จะช่วยให้มีกรณีเหล่านั้น
ravemir

1
มันเกือบจะสมบูรณ์แบบ ไม่ทำงานเมื่อ: อยู่ในหนึ่งในค่า
seler

9

ใช้ด้วยความระมัดระวัง (เพราะeval()):

function strToJson(str) {
  eval("var x = " + str + ";");
  return JSON.stringify(x);
}

โทรเป็น:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
alert( strToJson(str) );

3
ไปยังผู้ลงคะแนนที่ไม่ระบุชื่อ ฉันขอท้าให้คุณให้ทางออกที่ดีกว่า นอกจากนั้นเหตุผลของการลงคะแนนเสียงก็ดี
Tomalak

1
@Rocket: คุณผิด a) eval()เป็นวิธีเดียวที่จะทำ b) ฉันเตือน OP เกี่ยวกับมัน c) ดูคำตอบของ Matthew Crumley และคิดคำอธิบายที่ดีกว่า (โอ้และง) คำสั่งที่eval()ไม่ดีนั้นไร้สาระในแบบฟอร์มทั่วไปนี้)
Tomalak

2
@Rocket: อ่าเข้าใจผิดตรงนั้น ขออภัยฉันคิดว่าการลงคะแนนเสียงเป็นของคุณ :)
Tomalak

1
@kuboslav: มันใช้งานได้ดีคุณยังทดสอบมันได้หรือไม่ เขากำลังทำeval("var x = " + str + ";")สิ่งที่ถูกต้องโดยสิ้นเชิง var x = ({a:12})คุณไม่จำเป็นต้องที่จะทำ
Rocket Hazmat

2
@kuboslav มันไม่ทำงานใน IE7 เพราะ IE7 ไม่มีการสนับสนุน JSON ดั้งเดิม json2.jsมันจะเริ่มทำงานทันทีที่คุณใช้ อย่าทริกเกอร์มีความสุข
Tomalak

4

คำเตือน: อย่าลองทำที่บ้านหรือทำอะไรก็ตามที่ต้องมีการพัฒนาอย่างจริงจังเพื่อคุณ:

JSON.stringify(eval('(' + str + ')'));

ที่นั่นฉันทำมัน
พยายามที่จะไม่ทำมันสรรพสิ่งที่เลวร้ายสำหรับคุณ ตามที่ได้กล่าวไว้ข้างต้นให้ใช้ JSON shim สำหรับเบราว์เซอร์รุ่นเก่า (IE7 ขึ้นไป)

วิธีนี้ต้องการให้สตริงของคุณเป็นจาวาสคริปต์ที่ถูกต้องซึ่งจะถูกแปลงเป็นออบเจ็กต์จาวาสคริปต์ที่จะสามารถต่อเนื่องเป็น JSON

แก้ไข:แก้ไขตามที่แนะนำ Rocket


มันควรจะJSON.stringify(eval('('+str+')'));ไม่ใช่ว่าฉันเอาผิดevalแต่สตริงของเขาไม่ถูกต้อง JSON ดังนั้นจึงJSON.parseไม่ทำงาน
Rocket Hazmat

4

ฉันใส่คำตอบของฉันสำหรับคนที่สนใจในหัวข้อเก่านี้

ฉันสร้างHTML5 DATA- * parserสำหรับ jQuery ปลั๊กอินและสาธิตที่แปลงสตริง JSON ไม่ถูกต้องเป็นวัตถุ JavaScript eval()โดยไม่ต้องใช้

มันสามารถส่งผ่านตะโกนแอตทริบิวต์ HTML5 data- *:

<div data-object='{"hello":"world"}'></div>
<div data-object="{hello:'world'}"></div>
<div data-object="hello:world"></div>

เป็นวัตถุ:

{
    hello: "world"
}


2

มีวิธีที่ง่ายกว่ามากในการทำให้เพลงนี้สำเร็จเพียงจี้แอตทริบิวต์ onclick ขององค์ประกอบจำลองเพื่อบังคับให้ส่งคืนสตริงของคุณเป็นวัตถุ JavaScript:

var jsonify = (function(div){
  return function(json){
    div.setAttribute('onclick', 'this.__json__ = ' + json);
    div.click();
    return div.__json__;
  }
})(document.createElement('div'));

// Let's say you had a string like '{ one: 1 }' (malformed, a key without quotes)
// jsonify('{ one: 1 }') will output a good ol' JS object ;)

นี่คือตัวอย่าง: http://codepen.io/csuwldcat/pen/dfzsu (เปิดคอนโซลของคุณ)


2

คุณต้องใช้ "eval" จากนั้น JSON.stringify แล้ว JSON.parse กับผลลัพธ์

 var errorString= "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
 var jsonValidString = JSON.stringify(eval("(" + errorString+ ")"));
 var JSONObj=JSON.parse(jsonValidString);

ป้อนคำอธิบายรูปภาพที่นี่


1

คุณต้องเขียนวงเล็บเหลี่ยมเพราะหากไม่มีพวกเขาevalจะพิจารณารหัสภายในวงเล็บปีกกาเป็นบล็อกของคำสั่ง

var i = eval("({ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] })");

1

ทางออกที่ดีที่สุดและปลอดภัยที่สุดของคุณจะJSON5 - JSON สำหรับมนุษย์ มันถูกสร้างขึ้นโดยเฉพาะสำหรับกรณีการใช้งานที่

const result = JSON5.parse("{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }");

console.log(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/json5/0.5.1/json5.min.js"></script>


1

การใช้ Function ใหม่ () นั้นดีกว่า eval แต่ก็ควรใช้กับอินพุตที่ปลอดภัยเท่านั้น

const parseJSON = obj => Function('"use strict";return (' + obj + ')')();

console.log(parseJSON("{a:(4-1), b:function(){}, c:new Date()}"))
// outputs: Object { a: 3, b: b(), c: Date 2019-06-05T09:55:11.777Z }

แหล่งที่มา: MDN , 2ality


0

สำหรับตัวอย่างง่ายๆของคุณด้านบนคุณสามารถทำได้โดยใช้ 2 regex แบบง่ายแทน:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
str.replace(/(\w+):/g, '"$1":').replace(/'/g, '"');
 => '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

Big caveat : วิธีการที่ไร้เดียงสานี้อนุมานว่าวัตถุนั้นไม่มีสตริงที่มี'หรือ:อักขระ ตัวอย่างเช่นฉันไม่สามารถคิดวิธีที่ดีในการแปลง object-string ต่อไปนี้เป็น JSON โดยไม่ต้องใช้eval:

"{ hello: 'world', places: [\"America: The Progressive's Nightmare\"] }"

0

เพียงแค่นิสัยใจคอของมันคุณสามารถแปลงสตริงของคุณผ่าน babel-standalone

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";

function toJSON() {
  return {
    visitor: {
      Identifier(path) {
        path.node.name = '"' + path.node.name + '"'
      },
      StringLiteral(path) {
        delete path.node.extra
      }
    }
  }
}
Babel.registerPlugin('toJSON', toJSON);
var parsed = Babel.transform('(' + str + ')', {
  plugins: ['toJSON']
});
var json = parsed.code.slice(1, -2)
console.log(JSON.parse(json))
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>


0

var str = "{สวัสดี: 'โลก' สถานที่: ['แอฟริกา', 'อเมริกา', 'เอเชีย', 'ออสเตรเลีย']}" "var fStr = str .replace (/ ([Az] *) (:) / g, '"$ 1":') .replace (/ '/ g, "\" ")

console.log (JSON.parse (fStr))ป้อนคำอธิบายรูปภาพที่นี่

ขอโทษฉันอยู่ในโทรศัพท์ของฉันนี่คือรูป


0

วิธีการแก้ปัญหาด้วยหนึ่ง regex และไม่ได้ใช้ eval:

str.replace(/([\s\S]*?)(')(.+?)(')([\s\S]*?)/g, "$1\"$3\"$5")

สิ่งนี้ฉันเชื่อว่าควรใช้กับหลายบรรทัดและเหตุการณ์ที่เป็นไปได้ทั้งหมด (แฟล็ก / g) ของคำว่า 'string' แทนที่ด้วยคำว่า "string"



-1

บางทีคุณต้องลองสิ่งนี้:

str = jQuery.parseJSON(str)

คำถามที่ระบุ "หรือ jQuery" และนี่เป็นโซลูชันที่สมบูรณ์แบบหากคุณมีให้
Ecropolis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.