ウェブサイト検索

javascript - プロパティに引用符なしで JSON.stringify を使うには?


私は、プロパティにダブルクオートがないなど、間違ったJSON形式を使うサービスを利用しています。だから、送る必要があります

{ name: "John Smith" } は { "name": "John Smith" } の代わりに

これは私のサービスではないので、この形式は変更できません。

上のように JavaScript オブジェクトをフォーマットする stringify ルーティングを知っている人はいますか?

回答 #1

このシンプルな正規表現の解決策は、ほとんどの場合で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" }'

直してくれたロブ・Wに特別な感謝を。

制限

通常の場合、前述の正規表現は機能しますが、数学的には、すべてのケースで動作するように正規表現でJSON形式を記述することは不可能です(同じ数の波かっこを数えることは正規表現では不可能です)。したがって、ネイティブ関数を使用して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/

回答 #2

どうやら、あなたが探しているのはシンプルな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

オブジェクトを文字列化するか検査するかは、あなたのサーバーの言語に依存します。

回答 #3

要約 -- コード

ブラウザでの後方参照のサポートについての注意書きとともに、以下の通りです:

function cleanIt(obj) {
    var cleaned = JSON.stringify(obj, null, 2);

    return cleaned.replace(/^[\t ]*"[^:\n\r]+(?<!\\)":/gm, function (match) {
        return match.replace(/"/g, "");
    });
}

注意: ルックビハインドはIEではサポートされておらず、2021年6月18日時点で、奇妙なことにSafariのすべてのバージョンでもサポートされていません。そこで使用する場合は、正規表現から(?<!\)を削除し、下記に記載されている「注意すべき」条件に気を付けてください。

それは美しく文字列化し、私たちの正規表現を使ってキーを見つけ、その後各キーの一致は、すべての二重引用符を取り除いた「ここにあなたの一致があります」と言う置換関数によって置き換えられます。コロンまでしかキーを一致させていないので、それがまさに私たちが望むことです。

詳細な説明は以下の通りです。


なぜ承認された回答が正しくないのか

残念ながら、アデルが指摘しているように、デレクの正規表現を使わない解決策にはかなり深刻な問題があります。それはオブジェクトの配列を処理できません。配列の場合は JSON.stringify に任せる、という短絡的な処理になっているのがわかりますよね?これは単純な値の型には問題ありませんが、オブジェクトには適していません。

//                                        \/\/\/ OH NOES!!! \/\/\/
if (typeof obj_from_json !== "object" || Array.isArray(obj_from_json)){
    // not an object, stringify using native function
    
    return JSON.stringify(obj_from_json);
//         ^^^^^^^^^^^^^^ No! Don't do that! 
}

私は失敗ケースで彼のフィドルを編集しました。ペイロードはこちらです:

var obj = {
  name: "John Smith",
  favoriteObjects: [
    { b: "there's", c: "always", d: "something" },
    [1, 2, "spam", { f: "hello" }],
    { vowels: "are missing" },
  ],
  favoriteFruits: ["Apple", "Banana"],
};

そしてこちらが空白付きの出力です:

{
  name:"John Smith",
  favoriteObjects:[
    {
      "b":"there's",    <<< Major
      "c":"always",     <<< fails
      "d":"something"   <<< here
    },
    [
      1,2,"spam",
      {
        "f":"hello"     <<< and here.
      }
    ],
    {
      "vowels":"are missing" <<< again.
    }
  ],
  favoriteFruits:["Apple","Banana"] <<< that worked!
}

見てください。文字列の配列(favoriteFruits)は動作しますが、配列内のオブジェクト(例えば favoriteObjects)の二重シリアル化レベルではまだ引用符が付いてしまっています。良くないです。


簡単な解決策

その関数をきれいにしようとあまりにも長い時間を費やした後、問題の複雑さを大幅に減らす巧妙なトリックを見つけたので、それによって正規表現が再び関わってくると思います。

空白を含めてstringifyしましょう

マクガイア氏の言葉を借りれば、あなたに一言だけ言いたい、たった一言だけ:

空白。

空白を入れてJSON.stringifyを使いましょう。そうすると、キーから引用符を取り除く正規表現がずっと簡単になります。

これで解答を始めてください:

var cleaned = JSON.stringify(x, null, 2);

<code>stringify</code>の呼び出しは、<code>x</code>(最初のパラメータ)を、特別な置換関数を使わずに(2番目のパラメータが<code>null</code>であることを示す)、シリアライズの各階層に対して2つ(3番目のパラメータが<code>2</code>)のスペースを使って文字列化することを示しています。その<code>2</code>によって、各プロパティが別々の行に配置されます。

{
  "name": "John Smith",
  "favoriteObjects": [
    {
      "b": "there's",
      "c": "always",
// etc...

すべてのキーが今やきれいに行の先頭にあります。それは私たちが扱えます。


今すぐ キーから引用符を取り除いてください

キーだけを探し、その周囲の"を取り除く正規表現を作りましょう。キーがすべて独立した行にあることがわかっているので、物事ははるかに簡単です。

唯一の本当の落とし穴は、プロパティの値に途中で ": が含まれている場合です。それが問題を引き起こすことがあります。

"a": [
    "This could \": be bad",
    "QQ"
]

後方参照の注意

古いブラウザ向けに凝ったネガティブ・ルックアヘッドでこれを解決したかったのですが、諦めてネガティブ・ルックビハインドを使いました。ネガティブ・ルックビハインドは2018年以降の一部のブラウザでのみサポートされています(ルックビハインド提案の歴史の説明は2alityにあり、ブラウザの互換性はこちらで確認できます)。


正規表現の説明:

/^[\t ]*"[^:\n\r]+(?<!\\)":/gm

あの正規表現…

  • 正規表現です

    • /で始まります
  • (0から無限までのスペースまたはタブ)で始まる行を探します

    • ^[\t ]*
  • それから "

    • "
  • 次に、: でも改行文字でもない 任意の 1文字以上

    • [^:\n\r]+
  • それから、それは 2 文字 ": で終わります。ただし (否定の後読み警告) バックスラッシュに続かない

    • (?<!\\)":
    • JavaScriptにおける後読みについての詳細はこちら
  • これはグローバルに、かつ複数行(行ごとに)で行いますか

    • /gm

それなりに成功したフィドル。

結果:

{
  name: "John Smith",
  favoriteObjects: [
    {
      b: "there's",
      c: "always",
      d: "something"
    },
    [
      1,
      2,
      "spam",
      {
        f: "hello"
      }
    ],
    {
      vowels: "are missing"
    }
  ],
  favoriteFruits: [
    "Apple",
    "Banana"
  ]
}

ジャデントが尋ねてからわずか8年半でQED。これこそサービスだ!


クイックアップデート:もしこれをコード内で必ずしも実行する必要がない場合(ただし、いくつかのユースケースでは、このライブラリを直接呼び出すこともできます)、より良い答えとして、prettier を使用することができます。prettier は美しく整形してくれます。

回答 #4

JSON5.stringify を使用する

JSON5は、引用符なしのプロパティキーを含むES5構文を許可するJSONのスーパーセットです。JSON5のリファレンス実装(json5 npmパッケージ)は、組み込みのJSONオブジェクトと同じ引数と意味を持つ同じメソッドを備えたJSON5オブジェクトを提供します。

あなたが使用しているサービスは、このライブラリを使用している可能性が非常に高いです。実際、JSON5は多くの注目されているプロジェクトで使用されています:

JSON5は2012年に始まり、2022年時点で週に65M以上のダウンロードがあり、npmで最も依存されているパッケージの上位0.1%にランクインしており、Chromium、Next.js、Babel、Retool、WebStormなどの主要なプロジェクトでも採用されています。また、MacOSやiOSなどのAppleプラットフォームでもネイティブにサポートされています。

~ json5.org ホームページ

関連記事