JSONの修復
末尾カンマ、シングルクォート、コメント、Pythonリテラルを修正し、変更点を一覧表示します。
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
修復は、ほぼJSONになっているものを妥当なJSONにします。末尾カンマ、シングルクォート、クォートのないキー、コメント、Pythonのリテラル、全角の引用符、閉じていない括弧、目に見えない空白。
重要なのは出力ではなく、変更履歴です。ペイロードを黙って書き換える修復ツールは、修復ツールがないより悪い。何を勝手に判断されたのか分からないからです。すべての変更は行と列とともに一覧化され、判断を伴った変更は、伴わなかった変更とは別に表示されます。
推測せずに直せるもの
これらの解釈は一通りしかないため、変更履歴に記録する以外は黙って適用されます。
- 末尾カンマ・重複カンマ
- 削除します。JavaScriptとJSON5では合法ですが、JSONでは常に不正です。
- シングルクォートの文字列
- ダブルクォートに変換し、中身を再エスケープします。内部のアポストロフィで結果が壊れないようにするためです。
- クォートのないキー
- クォートを付けます。JavaScriptは裸の識別子をキーにできますが、JSONはできません。
- コメント
- // 形式も /* */ 形式も削除します。
- Pythonのリテラル
- True、False、Noneをtrue、false、nullにします。
- 全角・曲線の引用符
- オートコレクトが生成する曲がった引用符を、まっすぐなASCIIの引用符にします。
- 不正な空白
- ノーブレークスペースなどは通常のスペースに置き換え、ゼロ幅文字は削除します。
- バイトオーダーマーク
- ドキュメント先頭から取り除きます。
- 欠けたカンマとコロン
- 文法上、意図が一意に定まる位置に挿入します。
- 文字列内の生の制御文字
- エスケープします。生の改行は\nになります。
判断を伴うものとして明示するもの
これらは意味を変えます。万人にとって正しい既定値は存在しないため、適用したうえで別枠に記載し、設定で変更できます。
- 先頭のゼロ
- 既定では値をクォートします。02134は文字列"02134"になります。実データの先頭ゼロはほぼ必ず郵便番号、口座番号、SKUのいずれかで、削ると値が静かに壊れます。本当に数値なら、方針を「数値に変換」に切り替えると2134になります。
- NaN、Infinity、undefined
- nullに変換します。多くのエンコーダーが同じ置き換えをします。Pythonのjson.dumpsは既定でNaNとInfinityを出力するので、発生源で捕まえるにはallow_nan=Falseを渡してください。
- 値として使われた裸の単語
- 文字列としてクォートします。{"status": pending}は{"status": "pending"}になります。たいていは正しく、ときどきそうではありません。
- 閉じていない括弧
- ドキュメント末尾で閉じます。打ち間違いではなくファイルが途中で切れていた場合、これはデータが欠けたまま妥当なJSONを作ることになるため、この変更は必ず一覧に載せます。
- NDJSON
- 1行に1つずつ完結した値が並んでいる場合、既定では配列でまとめます。最初のレコードだけを残す、あるいは入力に手を加えない、という選択もできます。
やらないこと
構造を捏造することはしません。入力がJSONから遠すぎる場合、修復は失敗し、解決できなかったエラーを示します。パースは通るが意味を成さないものを作ることはありません。
また、パスの回数には上限があります。あるパスが前のパスで隠れていた問題を明らかにすることはありますが、処理はループせず収束します。
How to do this in code
コードで同じことをする方法と、正直な注意書き。受け取り側で寛容にパースしているということは、たいてい上流が不正なJSONを吐いており、これからも吐き続けるということです。
py Python、dictのrepr
ast.literal_evalはリテラル構造しか評価しないため、evalと違って任意のコードを実行できません。
import ast, json
# A Python dict printed with str() or print() is not JSON.
text = "{'name': 'Priya', 'active': True}"
value = ast.literal_eval(text) # safe: literals only, no eval
clean = json.dumps(value) # '{"name": "Priya", "active": true}' js JavaScript、JSON5
JSON5は仕様がきちんと定義された上位互換なので、その場しのぎの寛容なパーサーより適した移行先になります。
import JSON5 from 'json5';
// Accepts comments, trailing commas, unquoted keys, single
// quotes, hex numbers and more.
const value = JSON5.parse(text);
const strict = JSON.stringify(value); ts TypeScript、JSONC
import { parse } from 'jsonc-parser';
// What VS Code uses for its own settings files: comments and
// trailing commas, and nothing else.
const errors: ParseError[] = [];
const value = parse(text, errors); sh Shell
# Strip comments and trailing commas with jq's relaxed reader
jq --args . <<< "$text"
# Or normalise a JSON5 file
npx json5 -c config.json5 > config.json よくある質問
- 修復でデータが変わることはありますか?
- 「判断を伴うもの」に挙げた範囲でのみ変わり、そのすべてが行と列つきで変更履歴に載ります。安全な修復は構文にしか影響しません。判断内容に納得できない場合は、設定を変えて再実行してください。
- なぜ02134が数値2134ではなく文字列になるのですか?
- クォートは情報を失わず、ゼロを削るのは失うからです。実データの先頭ゼロはほぼ必ず意味を持っており、郵便番号を黙って小さい数値に変えてしまう変換は、まさにこのサイトが避けようとしている類いの静かな破壊です。削る設定はワンクリックで選べます。
- 修復できなかったと表示されました。どうすればよいですか?
- バリデーターに通してください。修復が扱うのは直し方が一意に決まる問題だけです。本当に復元不能な構造のドキュメントは、何を書こうとしていたのかを人が判断する必要があります。