JSON.stringify senza virgolette sulle proprietà?


95

Sto utilizzando un servizio che utilizza un formato JSON errato (senza virgolette doppie attorno alle proprietà). Quindi devo inviare

{ name: "John Smith" } invece di { "name": "John Smith" }

Questo formato non può essere modificato perché non è il mio servizio.

Qualcuno sa di un routing stringify per formattare un oggetto JavaScript come sopra?

Risposte:


115

Questa semplice soluzione di espressioni regolari funziona per deselezionare i nomi delle proprietà JSON nella maggior parte dei casi:

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

Caso estremo:

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

Un ringraziamento speciale a Rob W per averlo riparato.

Limitazioni

In casi normali la summenzionata regexp funzionerà, ma matematicamente è impossibile descrivere il formato JSON con un'espressione regolare tale che funzioni in ogni singolo caso (contare lo stesso numero di parentesi graffe è impossibile con regexp.) Pertanto, ho creare una nuova funzione per rimuovere le virgolette analizzando formalmente la stringa JSON tramite la funzione nativa e riserializzandola:

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

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


3
-1 non ero neanche io, ma devi leggere attentamente la domanda. OP deve codificare un oggetto in json (rotto), non analizzarlo / valutarlo.
Salman A

7
@Derek Questo metodo non è affidabile . Ad esempio, prendi questo input: {"foo":"e\":bar"}(JSON valido) diventa {foo:e:bar"}(...)!
Rob W

1
@Derek /\\\"/può essere semplificato in /\\"/. Non dimenticare di aggiungere il flag globale /\\"/g, o si interromperà su stringhe con più \". Per quanto riguarda il carattere casuale, non utilizzare mai un U + FFFF letterale, nel caso in cui l'editor si strozzi, ma una sequenza di escape. La regex per il ripristino diventerebbe /\uFFFF/g.
Rob W

2
@Derek 朕 會 功夫 la tua regex /\"([^(\")"]+)\":/gpuò essere semplificata /"([^"]+)":/g, vedi regex101.com/r/qnz0ld/2
tanguy_k

1
@endriu In tal caso è sufficiente aggiungere un ulteriore controllo per i valori nulli.
Derek 朕 會 功夫

18

Sembra che questo sia un semplice metodo Object toString che stai cercando.

In Node.js questo viene risolto utilizzando l'oggetto util e chiamando util.inspect (yourObject). Questo ti darà tutto ciò che desideri. seguire questo collegamento per ulteriori opzioni, inclusa la profondità dell'applicazione del metodo. http://nodejs.org/api/util.html#util_util_inspect_object_options

Quindi, quello che stai cercando è fondamentalmente un ispettore di oggetti non un convertitore JSON. Il formato JSON specifica che tutte le proprietà devono essere racchiuse tra virgolette doppie. Quindi non ci saranno convertitori JSON per fare quello che vuoi in quanto semplicemente non è un formato JSON.Specs qui: https://developer.mozilla.org/en-US/docs/Using_native_JSON

Oggetto da stringa o ispezione è ciò di cui hai bisogno a seconda della lingua del tuo server.


1
Grazie mille! Questo e 'esattamente quello che stavo cercando. Uso json per inviare dati attraverso il server ws al mio gioco e che ci crediate o no, non dovendo occuparmi delle virgolette extra intorno ai nomi delle proprietà si risparmia un'enorme quantità di dati! Giusto per chiarire, .toSource()funziona bene anche all'interno di nodejs, ma non funziona con gli oggetti negli array. L' utilispezione funziona per array e oggetti negli array, il che è meraviglioso, lo adoro.
NiCk Newman

3
util.inspect()ha funzionato benissimo per me mentre scrivevo un oggetto in una query Neo4j, per impostare più parametri contemporaneamente.
agm1984

1
Dal collegamento nodejs:> Il metodo util.inspect () restituisce una rappresentazione in formato stringa di un oggetto destinato al debug. L'output di util.inspect può cambiare in qualsiasi momento e non dovrebbe essere dipeso a livello di programmazione.
Peter Roehlen

5

Puoi guardare il codice sorgente di un parser creato da colui che ha definito il formato JSON . Cerca le chiamate di funzione: racchiudono un valore tra virgolette. Le chiavi sono citate alle righe 326 e 338json2.js quote .

Non includere la libreria dopo la modifica. Invece prendi solo la parte rilevante ( stringify), o almeno sostituisci JSONcon qualcos'altro, ad es.FAKEJSON.

Ad esempio, un oggetto FAKEJSONche ha definito solo stringify: http://jsfiddle.net/PYudw/


Perché avresti bisogno di una libreria extra quando puoi farlo in JavaScript puro?
Derek 朕 會 功夫

Questa è una buona idea. Avrei sborsare il repo, rimuovere le virgolette, e rinominare l'oggetto JSON a qualcosa di faceto come FAILJSON per mettere in chiaro che si sta non lavora con l'oggetto JSON reale, o JSON reale.
RichardTowers

@Derek La libreria non dovrebbe essere inclusa nella sua interezza. Prendi solo la JSON.stringifyparte e rimuovi le virgolette. Poiché la libreria è creata da colui che ha definito JSON , possiamo essere abbastanza sicuri che il risultato sia JSON molto valido.
Rob W

Sembra che questo sia l'approccio migliore.
Derek 朕 會 功夫

Sì, d'accordo con Derek. Sebbene il suo sostituto funzioni bene, mi sento più a mio agio con il codice di Crawford, senza mancare di rispetto a Derek lol. .toSource()funziona bene ma non include se il tuo oggetto è in un array che è un peccato (e sono sul nodo quindi la compatibilità del browser non è un problema: P) quindi userò questo metodo grazie anche a @RobW, il collegamento jsfiddle sembra essere bloccato alla pagina di caricamento :(
NiCk Newman

3

Prova a utilizzare il servizio con JSONP, immagino che lo offrano quando si utilizza questo formato.

Altrimenti, inviagli un rapporto dettagliato sui bug che includa una buona argomentazione sul perché dovrebbe essere conforme allo standard. Qualsiasi altra soluzione che eliminare il problema di origine non è una vera soluzione.

Una soluzione rapida e sporca potrebbe essere quella di collegare la stringa attraverso una regex prima di analizzarla:

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

Oppure provi a modificare un parser JSON javascript esistente (come questo ) se desideri un'analisi più sintattica.




2

@Derek 朕 會 功夫 Grazie per aver condiviso questo metodo, mi piacerebbe condividere il mio codice che supporta anche la stringa di un array di oggetti.

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
Dovresti usare anche JSON.stringifyper esempio Date. Restituisce anche 'null'se obj_from_jsonè nullo.
Far Dmitry

1
Ho appena risolto i punti sollevati da @FarDmitry modificando la seconda condizione if in questo modo:if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
Brunno Vodola Martins

2

Uso JSON5.stringify

JSON5 è un superset di JSON che consente la sintassi ES5, comprese le chiavi di proprietà non quotate . L'implementazione di riferimento JSON5 ( json5pacchetto npm ) fornisce un JSON5oggetto che ha gli stessi metodi con gli stessi argomenti e la stessa semantica JSONdell'oggetto incorporato .

È molto probabile che il servizio che stai utilizzando utilizzi questa libreria.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.