JSON.stringify ohne Anführungszeichen für Eigenschaften?

94

Ich verwende einen Dienst, der ein falsches JSON-Format verwendet (keine doppelten Anführungszeichen um Eigenschaften). Also muss ich senden

{ name: "John Smith" } anstatt { "name": "John Smith" }

Dieses Format kann nicht geändert werden, da dies nicht mein Dienst ist.

Kennt jemand ein Stringify-Routing zum Formatieren eines JavaScript-Objekts wie oben?

jadent
quelle

Antworten:

115

Diese einfache Lösung für reguläre Ausdrücke behebt in den meisten Fällen die Anführungszeichen von JSON-Eigenschaftsnamen:

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"}

Extremfall:

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

Besonderer Dank geht an Rob W für die Reparatur.

Einschränkungen

In normalen Fällen funktioniert der oben genannte reguläre Ausdruck, aber mathematisch ist es unmöglich, das JSON-Format mit einem regulären Ausdruck so zu beschreiben, dass es in jedem einzelnen Fall funktioniert (das Zählen der gleichen Anzahl von geschweiften Klammern ist mit regulärem Ausdruck unmöglich.) Daher habe ich Erstellen Sie eine neue Funktion, um Anführungszeichen zu entfernen, indem Sie die JSON-Zeichenfolge über die native Funktion formal analysieren und neu reserialisieren:

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}}`;
}

Beispiel: https://jsfiddle.net/DerekL/mssybp3k/

Derek 朕 會 功夫
quelle
3
-1 war ich auch nicht, aber du musst die Frage sorgfältig lesen. OP muss ein Objekt in (defektes) json codieren, nicht analysieren / auswerten.
Salman A
7
@Derek Diese Methode ist nicht zuverlässig . Nehmen Sie zum Beispiel diese Eingabe: {"foo":"e\":bar"}(gültiger JSON) wird {foo:e:bar"}(...)!
Rob W
1
@Derek /\\\"/kann vereinfacht werden /\\"/. Vergessen Sie nicht, das globale Flag hinzuzufügen /\\"/g, da es sonst bei mehreren Zeichenfolgen unterbrochen wird \". Verwenden Sie für das zufällige Zeichen niemals ein wörtliches U + FFFF, falls der Editor erstickt, sondern eine Escape-Sequenz. Der reguläre Ausdruck für das Zurücksetzen würde werden /\uFFFF/g.
Rob W
2
@Derek 朕 會 功夫 Ihre Regex /\"([^(\")"]+)\":/gkann vereinfacht werden /"([^"]+)":/g, siehe regex101.com/r/qnz0ld/2
tanguy_k
1
@endriu In diesem Fall fügen Sie einfach eine zusätzliche Prüfung für Nullwerte hinzu.
Derek 12 會 功夫
18

Es sieht so aus, als wäre dies eine einfache Object toString-Methode, nach der Sie suchen.

In Node.js wird dies gelöst, indem das util-Objekt verwendet und util.inspect (yourObject) aufgerufen wird. Dies gibt Ihnen alles, was Sie wollen. Folgen Sie diesem Link für weitere Optionen, einschließlich der Tiefe der Anwendung der Methode. http://nodejs.org/api/util.html#util_util_inspect_object_options

Was Sie also suchen, ist im Grunde ein Objektinspektor, kein JSON-Konverter. Das JSON-Format gibt an, dass alle Eigenschaften in doppelte Anführungszeichen gesetzt werden müssen. Daher wird es keine JSON-Konverter geben, die das tun, was Sie wollen, da dies einfach kein JSON-Format ist. Angaben hier: https://developer.mozilla.org/en-US/docs/Using_native_JSON

Abhängig von der Sprache Ihres Servers benötigen Sie ein Objekt für eine Zeichenfolge oder eine Überprüfung.

fino
quelle
1
Vielen Dank! Genau das habe ich gesucht. Ich verwende json, um Daten über den ws-Server an mein Spiel zu senden, und glaube es oder nicht. Wenn ich mich nicht mit den zusätzlichen Anführungszeichen um die Eigenschaftsnamen befassen muss, wird eine immense Datenmenge gespart! Nur zur Verdeutlichung, .toSource()funktioniert auch in nodejs einwandfrei, funktioniert jedoch nicht in Objekten in Arrays. Die utilInspektion funktioniert für Arrays und Objekte in Arrays, was wunderbar ist, ich liebe es.
NiCk Newman
3
util.inspect()Ich habe beim Schreiben eines Objekts in eine Neo4j-Abfrage einfach großartig funktioniert, um mehrere Parameter gleichzeitig festzulegen.
agm1984
1
Über den Knoten nodejs:> Die Methode util.inspect () gibt eine Zeichenfolgendarstellung des Objekts zurück, das zum Debuggen vorgesehen ist. Die Ausgabe von util.inspect kann sich jederzeit ändern und sollte nicht programmgesteuert abhängig sein.
Peter Roehlen
5

Sie können sich den Quellcode eines Parsers ansehen, der von demjenigen erstellt wurde, der das JSON-Format definiert hat . Suchen Sie nach Funktionsaufrufen: Diese umgeben einen Wert in Anführungszeichen. Die Schlüssel sind in den Zeilen 326 und 338 angegeben .json2.js quote

Schließen Sie die Bibliothek nach der Änderung nicht ein. Nehmen Sie stattdessen nur den relevanten ( stringify) Teil oder ersetzen Sie ihn zumindest durch JSONetwas anderes, z. FAKEJSON.

Zum Beispiel ein Objekt, FAKEJSONdas nur definiert hat stringify: http://jsfiddle.net/PYudw/

Rob W.
quelle
Warum benötigen Sie eine zusätzliche Bibliothek, wenn Sie dies in reinem JavaScript tun können?
Derek 27 會 功夫
Das ist eine gute Idee. Ich würde das Repo aufteilen, die Anführungszeichen entfernen und das JSON-Objekt in etwas Scherzhaftes wie FAILJSON umbenennen, um klar zu machen, dass Sie nicht mit dem tatsächlichen JSON-Objekt oder dem tatsächlichen JSON arbeiten.
RichardTowers
@Derek Die Bibliothek sollte nicht als Ganzes enthalten sein. Nehmen Sie nur das JSON.stringifyTeil und entfernen Sie die Anführungszeichen. Da die Bibliothek von demjenigen erstellt wird, der JSON definiert hat , können wir ziemlich sicher sein, dass das Ergebnis sehr gültiges JSON ist.
Rob W
Sieht so aus, als wäre dies der beste Ansatz.
Derek 27 會 功夫
Ja, stimme Derek zu. Obwohl sein Ersatz gut funktioniert, bin ich mit Crawfords Code sicherer, ohne Respektlosigkeit gegenüber Derek Lol. .toSource()funktioniert gut, schließt aber nicht ein, wenn sich Ihr Objekt in einem Array befindet, das ein Mist ist (und ich bin auf dem Knoten, so dass die Browserkompatibilität kein Problem darstellt: P), also werde ich diese Methode verwenden, danke auch an @RobW, der jsfiddle-Link scheint auf der
Ladeseite
3

Versuchen Sie, den Dienst mit JSONP zu verwenden. Ich denke, sie bieten ihn an, wenn Sie dieses Format verwenden.

Andernfalls reichen Sie ihnen einen detaillierten Fehlerbericht mit einer guten Argumentation ein, warum die dem Standard entsprechen sollten. Eine andere Lösung als die Beseitigung des Quellproblems ist keine echte Lösung.

Eine schnelle Lösung könnte darin bestehen, den String vor dem Parsen durch einen regulären Ausdruck zu leiten:

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

Oder Sie versuchen, einen vorhandenen Javascript-JSON-Parser (wie diesen ) anzupassen, wenn Sie eine syntaktischere Analyse wünschen.

Bergi
quelle
3

Ich habe ein gutes NPM-Paket gefunden, um genau dies zu tun:

https://www.npmjs.com/package/stringify-object

const stringify = require('stringify-object')

let prettyOutput = stringify(json);

Funktioniert ziemlich gut.

user1543276
quelle
1
Diese Bibliothek ist nicht rekursiv.
Corysimmons
2

Ihre geerbte Syntax sollte von YAML, einer Obermenge von JSON, leicht zu essen sein.

Probieren Sie den JavaScript YAML Parser und Dumper aus: http://nodeca.github.com/js-yaml/

user1649339
quelle
2

@Derek 朕 會 功夫 Vielen Dank, dass Sie diese Methode freigegeben haben. Ich möchte meinen Code freigeben, der auch das Stringifizieren eines Arrays von Objekten unterstützt.

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(",")
            }}`;
};
Adel Bachene
quelle
1
Sie sollten JSON.stringifyzum Beispiel auch Datum verwenden. Geben Sie auch zurück, 'null'wenn obj_from_jsonnull ist.
Far Dmitry
1
Ich habe gerade die von @FarDmitry angesprochenen Punkte behoben, indem ich die zweite if-Bedingung so if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
geändert habe
2

Verwenden JSON5.stringify

JSON5 ist eine Obermenge von JSON, die ES5-Syntax einschließlich nicht zitierter Eigenschaftsschlüssel ermöglicht. Die JSON5-Referenzimplementierung ( json5npm-Paket ) bietet ein JSON5Objekt mit denselben Methoden und denselben Argumenten und derselben gleichen Semantik wie das integrierte JSONObjekt.

Es ist sehr wahrscheinlich, dass der von Ihnen verwendete Dienst diese Bibliothek verwendet.

Inigo
quelle