JSON.stringify โดยไม่มีเครื่องหมายคำพูดเกี่ยวกับคุณสมบัติ?


98

ฉันใช้บริการที่ใช้รูปแบบ JSON ที่ไม่ถูกต้อง (ไม่มีเครื่องหมายคำพูดคู่รอบคุณสมบัติ) เลยต้องส่ง

{ name: "John Smith" } แทน { "name": "John Smith" }

ไม่สามารถเปลี่ยนแปลงรูปแบบนี้ได้เนื่องจากนี่ไม่ใช่บริการของฉัน

มีใครทราบบ้างเกี่ยวกับการกำหนดเส้นทาง stringify เพื่อจัดรูปแบบวัตถุ JavaScript เช่นด้านบน?

คำตอบ:


118

โซลูชันนิพจน์ทั่วไปที่เรียบง่ายนี้ใช้ได้กับการยกเลิกการอ้างชื่อคุณสมบัติ JSON ในกรณีส่วนใหญ่:

const object = { name: 'John Smith' };
const json = JSON.stringify(object);  // {"name":"John Smith"}
console.log(json);
const unquoted = json.replace(/"([^"]+)":/g, '$1:');
console.log(unquoted);  // {name:"John Smith"}

กรณีที่รุนแรง:

var json = '{ "name": "J\\":ohn Smith" }'
json.replace(/\\"/g,"\uFFFF");  // U+ FFFF
json = json.replace(/"([^"]+)":/g, '$1:').replace(/\uFFFF/g, '\\\"');
// '{ name: "J\":ohn Smith" }'

ขอขอบคุณเป็นพิเศษสำหรับ Rob W สำหรับการแก้ไข

ข้อ จำกัด

ในกรณีปกติ regexp ดังกล่าวข้างต้นจะใช้งานได้ แต่ในทางคณิตศาสตร์เป็นไปไม่ได้ที่จะอธิบายรูปแบบ JSON ด้วยนิพจน์ทั่วไปซึ่งจะใช้งานได้ในทุกกรณี (การนับวงเล็บปีกกาจำนวนเท่ากันเป็นไปไม่ได้ด้วย regexp) ดังนั้นฉันมี สร้างฟังก์ชั่นใหม่เพื่อลบเครื่องหมายคำพูดโดยการแยกวิเคราะห์สตริง JSON อย่างเป็นทางการผ่านฟังก์ชันเนทีฟและกำหนดค่าใหม่อีกครั้ง:

function stringify(obj_from_json) {
    if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
        // not an object, stringify using native function
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    let props = Object
        .keys(obj_from_json)
        .map(key => `${key}:${stringify(obj_from_json[key])}`)
        .join(",");
    return `{${props}}`;
}

ตัวอย่าง: https://jsfiddle.net/DerekL/mssybp3k/


3
-1 ไม่ใช่ฉันเหมือนกัน แต่คุณต้องอ่านคำถามอย่างละเอียด OP จำเป็นต้องเข้ารหัสวัตถุเป็น (เสีย) json ไม่ใช่แยกวิเคราะห์ / ประเมิน
Salman A

7
@Derek วิธีนี้ไม่น่าเชื่อถือ ตัวอย่างเช่นรับอินพุตนี้: {"foo":"e\":bar"}(JSON ที่ถูกต้อง) กลายเป็น{foo:e:bar"}(... )!
Rob W

1
@Derek /\\\"/สามารถทำให้ง่าย/\\"/ขึ้นได้ อย่าลืมที่จะเพิ่มธงชาติทั่วโลกหรือมันจะทำลายในสายที่มีหลาย/\\"/g \"ในฐานะที่เป็นตัวอักษรแบบสุ่มไม่เคยใช้ตัวอักษร U + FFFF ในกรณีฉายาบรรณาธิการ แต่ลำดับหนี regex /\uFFFF/gสำหรับย้อนกลับจะกลายเป็น
Rob W

2
@Derek 朕會功夫 regex ของคุณ/\"([^(\")"]+)\":/gสามารถทำให้ง่าย/"([^"]+)":/gขึ้นได้ดูที่regex101.com/r/qnz0ld/2
tanguy_k

1
@endriu ในกรณีนั้นให้เพิ่มการตรวจสอบค่าว่างเพิ่มเติม
Derek 朕會功夫

18

ดูเหมือนว่านี่จะเป็นวิธี Object toString ง่ายๆที่คุณกำลังมองหา

ใน Node.js สิ่งนี้แก้ไขได้โดยใช้อ็อบเจ็กต์ util และเรียก util.inspect (yourObject) สิ่งนี้จะให้ทุกสิ่งที่คุณต้องการ ไปที่ลิงค์นี้เพื่อดูตัวเลือกเพิ่มเติมรวมถึงความลึกของการใช้วิธีการ http://nodejs.org/api/util.html#util_util_inspect_object_options

ดังนั้นสิ่งที่คุณกำลังมองหาคือตัวตรวจสอบวัตถุไม่ใช่ตัวแปลง JSON รูปแบบ JSON ระบุว่าคุณสมบัติทั้งหมดต้องอยู่ในเครื่องหมายคำพูดคู่ ดังนั้นจะไม่มีตัวแปลง JSON ที่จะทำสิ่งที่คุณต้องการเนื่องจากไม่ใช่รูปแบบ JSON สเปคที่นี่: https://developer.mozilla.org/en-US/docs/Using_native_JSON

Object to string หรือการตรวจสอบคือสิ่งที่คุณต้องการขึ้นอยู่กับภาษาของเซิร์ฟเวอร์ของคุณ


1
ขอบคุณมาก! นี่คือสิ่งที่ฉันกำลังมองหา ฉันใช้ json เพื่อส่งข้อมูลผ่านเซิร์ฟเวอร์ ws ไปยังเกมของฉันและเชื่อหรือไม่ว่าการไม่ต้องจัดการกับเครื่องหมายคำพูดพิเศษรอบ ๆ ชื่อคุณสมบัติจะช่วยประหยัดข้อมูลได้มหาศาล! เพียงเพื่อชี้แจง.toSource()ทำงานได้ดีภายใน nodejs เช่นกัน แต่ไม่ทำงานวัตถุในอาร์เรย์ การutilตรวจสอบทำงานสำหรับอาร์เรย์และวัตถุในอาร์เรย์ที่ยอดเยี่ยมรักมัน
NiCk Newman

3
util.inspect()ใช้งานได้ยอดเยี่ยมสำหรับฉันในขณะที่เขียนวัตถุลงในแบบสอบถาม Neo4j เพื่อตั้งค่าพารามิเตอร์หลายรายการพร้อมกัน
agm1984

1
จากลิงค์ nodejs:> วิธี util.inspect () ส่งคืนการแสดงสตริงของอ็อบเจ็กต์ที่มีไว้สำหรับการดีบัก ผลลัพธ์ของ util.inspect อาจเปลี่ยนแปลงได้ตลอดเวลาและไม่ควรขึ้นอยู่กับการเขียนโปรแกรม
Peter Roehlen

5

คุณสามารถดูรหัสที่มาของparser ที่สร้างขึ้นโดยคนที่กำหนดรูปแบบ มองหาการเรียกใช้ฟังก์ชัน: สิ่งเหล่านี้ล้อมรอบค่าด้วยเครื่องหมายคำพูด คีย์จะถูกยกมาที่สาย326และ338json2.js quote

อย่ารวมไลบรารีหลังการแก้ไข แทนที่จะใช้เฉพาะส่วนที่เกี่ยวข้อง ( stringify) หรืออย่างน้อยก็แทนที่JSONด้วยอย่างอื่นเช่น FAKEJSON.

ตัวอย่างเช่นวัตถุFAKEJSONที่กำหนดเฉพาะstringify: http://jsfiddle.net/PYudw/


ทำไมคุณต้องมีไลบรารีเพิ่มเติมในเมื่อคุณสามารถทำได้ด้วย JavaScript บริสุทธิ์?
Derek 朕會功夫

นี่เป็นความคิดที่ดี ฉันจะแยก repo ลบเครื่องหมายคำพูดและเปลี่ยนชื่อวัตถุ JSON เป็นสิ่งที่มองไม่เห็นเช่น FAILJSON เพื่อให้ชัดเจนว่าคุณไม่ได้ทำงานกับวัตถุ JSON จริงหรือ JSON จริง
RichardTowers

@Derek ไม่ควรรวมไลบรารีไว้ทั้งหมด รับเฉพาะJSON.stringifyส่วนและลบเครื่องหมายคำพูด เนื่องจากไลบรารีถูกสร้างขึ้นโดยผู้กำหนด JSONเราจึงมั่นใจได้ว่าผลลัพธ์เป็น JSON ที่ถูกต้องมาก
Rob W

ดูเหมือนว่านี่จะเป็นแนวทางที่ดีที่สุด
Derek 朕會功夫

ใช่เห็นด้วยกับ Derek แม้ว่าตัวเปลี่ยนของเขาจะทำงานได้ดี แต่ฉันก็รู้สึกมั่นใจกับรหัสของครอว์ฟอร์ดมากขึ้นไม่ต้องดูหมิ่นดูแคลน .toSource()ใช้งานได้ดี แต่ไม่รวมถ้าวัตถุของคุณอยู่ในอาร์เรย์ซึ่งเป็นคนเกียจคร้าน (และฉันอยู่ในโหนดดังนั้นความเข้ากันได้ของเบราว์เซอร์จึงไม่ใช่ปัญหา: P) ดังนั้นฉันจะใช้วิธีนี้ขอบคุณ @RobW ด้วยเช่นกันลิงก์ jsfiddle ติดอยู่ที่หน้าโหลด :(
NiCk Newman

4

ลองใช้ servive กับ JSONP ฉันเดาว่าพวกเขาเสนอเมื่อใช้รูปแบบนี้

มิฉะนั้นให้ยื่นรายงานข้อบกพร่องโดยละเอียดรวมถึงข้อโต้แย้งที่ดีว่าเหตุใดจึงควรเป็นไปตามมาตรฐาน วิธีแก้ปัญหาอื่น ๆ นอกเหนือจากการขจัดปัญหาต้นทางนั้นไม่มีทางแก้ได้จริง

การแก้ไขอย่างรวดเร็ว n-dirty อาจเป็นการไพพ์สตริงผ่าน regex ก่อนที่จะแยกวิเคราะห์:

var obj = JSON.parse(str.replace(/(\{|,)\s*(.+?)\s*:/g, '$1 "$2":'));

หรือคุณพยายามปรับตัวแยกวิเคราะห์ javascript JSON ที่มีอยู่ (เช่นนี้ ) หากคุณต้องการแยกวิเคราะห์เชิงไวยากรณ์เพิ่มเติม




2

@Derek 朕會功夫ขอบคุณสำหรับการแบ่งปันวิธีนี้ฉันต้องการแบ่งปันรหัสของฉันซึ่งรองรับการสร้างอาร์เรย์ของวัตถุด้วย

export const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
    // In case of an array we'll stringify all objects.
    if (Array.isArray(obj_from_json)) {
        return `[${
                    obj_from_json
                        .map(obj => `${stringifyObjectWithNoQuotesOnKeys(obj)}`)
                        .join(",")
                }]` ;
    }
    // not an object, stringify using native function
    if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null){
        return JSON.stringify(obj_from_json);
    }
    // Implements recursive object serialization according to JSON spec
    // but without quotes around the keys.
    return `{${
            Object
                .keys(obj_from_json)
                .map(key => `${key}:${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`)
                .join(",")
            }}`;
};

1
คุณควรใช้JSON.stringifyเช่นวันที่ด้วย ยังส่งคืน'null'หากobj_from_jsonเป็นโมฆะ
Far Dmitry

1
ฉันเพิ่งแก้ไขจุดที่เพิ่มขึ้นโดย @FarDmitry โดยการเปลี่ยนเงื่อนไขที่สองหากมีลักษณะเช่นนี้:if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
Brunno Vodola Martins

2

ใช้ JSON5.stringify

JSON5เป็น superset ของ JSON ที่ช่วยให้ ES5 ไวยากรณ์รวมทั้งunquotedปุ่มคุณสมบัติ การใช้งานอ้างอิง JSON5 (json5แพ็กเกจ npm ) จัดเตรียมJSON5อ็อบเจ็กต์ที่มีเมธอดเดียวกันกับ args และ semantics เดียวกันกับJSONอ็อบเจ็กต์ในตัว

เป็นไปได้สูงว่าบริการที่คุณใช้อยู่กำลังใช้ไลบรารีนี้


1

JSON Beautifier ของ CSVJSONมีตัวเลือกในการวางเครื่องหมายคำพูดบนคีย์ หากคุณต้องการเพียงแค่รหัสคุณสามารถคัดลอกได้จาก repo GitHub ฉันแก้ไข JSON2 ของ Douglas Crockfordเพื่อเพิ่มการสนับสนุนสำหรับสิ่งนั้น


เพียงคลิกที่csvjson.com/json_beautifierและได้รับหน้าเว็บที่แตกต่างจากที่ฉันคาดไว้ ... hacked by AnoaGhost
RedactedProfile

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