JSON.stringify sem aspas nas propriedades?

95

Estou usando um serviço que usa o formato JSON incorreto (sem aspas duplas nas propriedades). Então eu preciso enviar

{ name: "John Smith" } ao invés de { "name": "John Smith" }

Este formato não pode ser alterado porque este não é o meu serviço.

Alguém sabe de um roteamento stringify para formatar um objeto JavaScript como acima?

cansado
fonte

Respostas:

115

Esta solução simples de expressão regular funciona para remover aspas nomes de propriedades JSON na maioria dos casos:

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 extremo:

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

Agradecimentos especiais a Rob W por consertá-lo.

Limitações

Em casos normais, a expressão regular mencionada funcionará, mas matematicamente é impossível descrever o formato JSON com uma expressão regular de forma que funcione em todos os casos (contar o mesmo número de chaves é impossível com a expressão regular.) Portanto, eu tenho crie uma nova função para remover aspas, analisando formalmente a string JSON por meio da função nativa e reerialize-a:

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

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

Derek 朕 會 功夫
fonte
3
- Eu também não fui eu, mas você deve ler a pergunta com atenção. O OP precisa codificar um objeto para json (quebrado), não analisá-lo / avaliá-lo.
Salman A
7
@Derek Este método não é confiável . Por exemplo, pegue esta entrada: {"foo":"e\":bar"}(JSON válido) torna-se {foo:e:bar"}(...)!
Rob W
1
@Derek /\\\"/pode ser simplificado para /\\"/. Não se esqueça de adicionar o sinalizador global /\\"/g, ou ele quebrará em strings com vários \". Já para o caractere aleatório, nunca use um literal U + FFFF, caso o editor engasgue, mas sim uma seqüência de escape. A regex para reversão se tornaria /\uFFFF/g.
Rob W
2
@Derek 朕 會 功夫 sua regex /\"([^(\")"]+)\":/gpode ser simplificada /"([^"]+)":/g, consulte regex101.com/r/qnz0ld/2
tanguy_k
1
@endriu Nesse caso, basta adicionar uma verificação adicional para valores nulos.
Derek 朕 會 功夫
18

Parece que este é um método Object toString simples que você está procurando.

No Node.js, isso é resolvido usando o objeto util e chamando util.inspect (yourObject). Isso lhe dará tudo o que você deseja. siga este link para mais opções, incluindo a profundidade da aplicação do método. http://nodejs.org/api/util.html#util_util_inspect_object_options

Portanto, o que você está procurando é basicamente um inspetor de objetos, não um conversor JSON. O formato JSON especifica que todas as propriedades devem ser colocadas entre aspas duplas. Portanto, não haverá conversores JSON para fazer o que você deseja, pois simplesmente não é um formato JSON. Especifique aqui: https://developer.mozilla.org/en-US/docs/Using_native_JSON

Objeto para string ou inspeção é o que você precisa, dependendo do idioma do seu servidor.

fino
fonte
1
Muito obrigado! Isso é exatamente o que eu estava procurando. Eu uso json para emitir dados através do servidor ws para o meu jogo e acredite ou não, não ter que lidar com as aspas extras em torno dos nomes das propriedades economiza uma quantidade imensa de dados! Só para esclarecer, .toSource()funciona bem com nodejs também, mas não funciona com objetos em arrays. A utilinspeção funciona para arrays e objetos em arrays, o que é maravilhoso, adorei.
NiCk Newman
3
util.inspect()funcionou muito bem para mim ao escrever um objeto em uma consulta Neo4j, para definir vários parâmetros de uma vez.
agm1984
1
No link nodejs:> O método util.inspect () retorna uma representação de string do objeto que se destina à depuração. A saída de util.inspect pode mudar a qualquer momento e não deve ser dependente de programação.
Peter Roehlen
5

Você pode olhar o código-fonte de um analisador criado por aquele que definiu o formato JSON . Procure chamadas de função: elas cercam um valor entre aspas. As chaves são citadas nas linhas 326 e 338 .json2.js quote

Não inclua a biblioteca após a modificação. Em vez disso, pegue apenas a parte relevante ( stringify) ou pelo menos substitua JSONpor outra coisa, por exemplo. FAKEJSON.

Por exemplo, um objeto FAKEJSONque definiu apenas stringify: http://jsfiddle.net/PYudw/

Rob W
fonte
Por que você precisa de uma biblioteca extra quando pode fazer isso em JavaScript puro?
Derek 朕 會 功夫
Essa é uma boa ideia. Gostaria de bifurcar o repo, remover as aspas e renomear o objeto JSON para algo jocoso como FAILJSON para deixar claro que você não está trabalhando com o objeto JSON real ou JSON real.
RichardTowers
@Derek A biblioteca não deve ser incluída como um todo. Pegue apenas a JSON.stringifyparte e remova as aspas. Como a biblioteca é criada por quem definiu JSON , podemos ter certeza de que o resultado é um JSON muito válido.
Rob W
Parece que essa é a melhor abordagem.
Derek 朕 會 功夫
Sim, concordo com Derek. Embora seu substituto funcione bem, eu me sinto mais confiante com o código do crawford, sem desrespeito ao derek lol. .toSource()funciona bem, mas não inclui se o seu objeto está no array, o que é uma chatice (e eu estou no nó, então a compatibilidade do navegador não é um problema: P) então vou usar este método obrigado @RobW também, o link jsfiddle parece ficar preso na página de carregamento :(
NiCk Newman
3

Tente usar o servive com JSONP, acho que eles oferecem ao usar este formato.

Caso contrário, envie-lhes um relatório de bug detalhado, incluindo uma boa argumentação sobre porque o deve estar em conformidade com o padrão. Qualquer outra solução além de eliminar o problema de origem não é uma solução real.

Uma solução rápida e suja pode ser canalizar a string por meio de uma regex antes de analisá-la:

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

Ou tente ajustar um analisador JSON javascript existente (como este ) se quiser uma análise mais sintática.

Bergi
fonte
3

Encontre um bom pacote de NPM para fazer exatamente isso:

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

const stringify = require('stringify-object')

let prettyOutput = stringify(json);

Funciona muito bem.

user1543276
fonte
1
Esta biblioteca não é recursiva.
corysimmons
2

Sua sintaxe herdada deve ser facilmente comida por YAML, que é um superconjunto de JSON.

Experimente o analisador e dumper JavaScript YAML: http://nodeca.github.com/js-yaml/

user1649339
fonte
2

@Derek 朕 會 功夫 Obrigado por compartilhar este método, gostaria de compartilhar meu código, que suporta a stringificação de um array de objetos também.

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
fonte
1
Você deve usar JSON.stringifypor exemplo Data também. Também retorna 'null'se obj_from_jsonfor nulo.
Far Dmitry
1
Acabei de consertar os pontos levantados por @FarDmitry mudando a segunda condição if para ficar assim:if(typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null)
Brunno Vodola Martins
2

Usar JSON5.stringify

JSON5 é um superconjunto de JSON que permite a sintaxe ES5, incluindo chaves de propriedade não citadas . A implementação de referência JSON5 ( json5pacote npm ) fornece um JSON5objeto que tem os mesmos métodos com os mesmos argumentos e semânticas do JSONobjeto integrado .

É muito provável que o serviço que você está usando esteja usando esta biblioteca.

Inigo
fonte