はじめに (対象読者・この記事でわかること)
この記事は、JavaScriptで開発を行っている中級者〜上級者の方を対象としています。特にAPI連携やデータ処理の際にJSON形式のデータを扱う機会が多い開発者に最適です。この記事を読むことで、JSON.parseが形式上は正しいのにエラーになる原因を理解し、具体的な解決策を実践できるようになります。多くの開発者が時間を浪費しているこの問題を効率的に解決する方法を学び、デバッグスキルを向上させることができます。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - JavaScriptの基本的な知識 - JSONの基本的な構造と形式 - 非同期処理(Promiseやasync/await)の基本的な理解 - コンソールでのデバッグ経験
JSON.parseがエラーになる原因と背景
JavaScript開発において、JSON.parse()は非常に基本的で重要な関数です。サーバーから受け取った文字列データをJavaScriptオブジェクトに変換する際に頻繁に使用されます。しかし、多くの開発者が経験するのは、文字列を確認するとJSON形式として問題ないように見えるにもかかわらず、JSON.parse()でエラーが発生するという状況です。
この問題は、見た目では発見しにくい様々な原因が考えられます。代表的な原因として、文字列の前後に存在する余分な空白文字、引用符の不一致、余分なカンマ、特殊文字の問題、文字コードの問題(特にBOM付きUTF-8)などが挙げられます。これらの問題は、開発ツールで文字列を直接確認しても気づきにくいため、デバッグに時間を要するケースが少なくありません。
また、APIから返されるデータは、仕様上はJSON形式であることが保証されていても、実際には前処理や通信プロトコルの問題で意図しない文字列が含まれていることがあります。特に、CORSやセキュリティヘッダーが絡む通信では、プレーンなJSONとは異なるフォーマットでデータが返されることもあります。
JSON.parseエラーの具体的な原因と解決策
余分な空白文字と改行によるエラー
JSON.parse()は、文字列の前後に余分な空白文字や改行がある場合にエラーを返すことがあります。これは特に、テキストエディタでJSONを整形した際や、サーバーから返されるデータが前処理によって加工されている場合に発生しやすい問題です。
Javascript// エラーになる例 const invalidJson = " {\"name\":\"Taro\",\"age\":30} "; try { const result = JSON.parse(invalidJson); console.log(result); } catch (e) { console.error("エラー:", e.message); } // 解決策:trim()で前後の空白を除去 const validJson = invalidJson.trim(); const result = JSON.parse(validJson); // 成功
解決策:
文字列をパースする前に、trim()メソッドを使用して前後の空白文字を除去するのが最も簡単な方法です。また、正規表現を使用してすべての空白文字を除去することも可能ですが、JSONの構造を維持するために必要な空白まで除去しないように注意が必要です。
Javascript// より堅牢な前処理 function safeJsonParse(jsonString) { // 前後の空白を除去 const trimmed = jsonString.trim(); try { return JSON.parse(trimmed); } catch (e) { console.error("JSONパースエラー:", e); return null; } }
引用符の不一致とエスケープシーケンスの問題
JSONでは、キーと文字列値は二重引用符(")で囲む必要がありますが、JavaScriptの文字列リテラルでは単一引用符(')も使用できます。この違いにより、意図せず引用符が混在することがあります。
Javascript// 引用符の不一致によるエラー const invalidJson = "{'name':'Taro','age':30}"; // 単一引用符を使用 // 解決策:正規表現で単一引用符を二重引用符に置換 const fixedJson = invalidJson.replace(/'/g, '"'); const result = JSON.parse(fixedJson); // 成功
また、文字列内に含まれる特殊文字やエスケープシーケンスが不正な場合にもエラーが発生します。
Javascript// 不正なエスケープシーケンス const invalidJson = "{\"name\":\"Taro\",\"message\":\"This is a backslash: \\\"}"; // エスケープ不足 // 解決策:エスケープシーケンスを修正 const fixedJson = "{\"name\":\"Taro\",\"message\":\"This is a backslash: \\\\\"}"; const result = JSON.parse(fixedJson); // 成功
解決策: 引用符の不一致が疑われる場合は、正規表現を使用して単一引用符を二重引用符に置換します。また、エスケープシーケンスの問題については、文字列をエンコード・デコードすることで解決できる場合があります。
Javascriptfunction fixJsonString(jsonString) { // 単一引用符を二重引用符に置換 let fixed = jsonString.replace(/'/g, '"'); // エスケープシーケンスの問題を修正 fixed = fixed.replace(/\\([^"\\/bfnrtu])/g, '\\\\$1'); return fixed; }
余分なカンマによるエラー
JSONでは、オブジェクトや配列の最後にカンマを置くことは許可されていません。しかし、JavaScriptのオブジェクトリテラルでは許可されているため、意図せず余分なカンマが含まれることがあります。
Javascript// 余分なカンマによるエラー const invalidJson = "{\"name\":\"Taro\",\"age\":30,}"; // 最後にカンマがある // 解決策:正規表現で余分なカンマを除去 const fixedJson = invalidJson.replace(/,(\s*[}\]])/g, '$1'); const result = JSON.parse(fixedJson); // 成功
解決策: 正規表現を使用して、オブジェクトや配列の終端直前の余分なカンマを除去します。この方法は、ネストされた構造にも対応できます。
Javascriptfunction removeTrailingCommas(jsonString) { return jsonString.replace(/,(\s*[}\]])/g, '$1'); }
文字コードとBOMの問題
特にWindows環境で作成されたファイルや、特定のエディタで保存されたJSONには、BOM(Byte Order Mark)が含まれていることがあります。BOMはUTF-8でエンコードされたテキストファイルの先頭に挿入される特殊な文字列で、JSON.parse()では認識されないためエラーの原因となります。
Javascript// BOM付きの文字列(実際にはバイト列として扱われる) const bomUtf8 = "\ufeff{\"name\":\"Taro\"}"; // 解決策:BOMを除去 const fixedJson = bomUtf8.replace(/^\ufeff/, ''); const result = JSON.parse(fixedJson); // 成功
解決策:
BOMを除去するには、文字列の先頭にある\ufeffを削除します。また、ファイルを読み込む際にBOMを自動で処理できるライブラリ(iconv-liteなど)を使用する方法もあります。
Javascriptfunction removeBOM(jsonString) { return jsonString.replace(/^\ufeff/, ''); }
数値表現の問題
JSONでは、数値は特定の形式で表現する必要があります。特に、科学表記法や非常に大きな数、非常に小さな数は、実装によっては問題を引き起こすことがあります。
Javascript// 科学表記法によるエラー(一部の環境) const invalidJson = "{\"bigNumber\":1e309}"; // 数値が大きすぎる // 解決策:数値を文字列として扱い、後で変換 const fixedJson = "{\"bigNumber\":\"1e309\"}"; const parsed = JSON.parse(fixedJson); const result = { ...parsed, bigNumber: Number(parsed.bigNumber) }; // 数値に変換
解決策: 数値が問題となる場合は、数値を文字列としてパースし、後で適切な型に変換する方法が有効です。
完全なJSON形式ではないデータの処理
APIから返されるデータが、完全なJSONオブジェクトではなく、配列やプリミティブ値である場合があります。また、エラーレスポンスとしてJSONではなくプレーンテキストが返されることもあります。
Javascript// 完全なJSON形式ではないデータ const notFullJson = "{\"name\":\"Taro\""; // 閉じ括弧がない // 解決策:try-catchでエラーを処理 let result; try { result = JSON.parse(notFullJson); } catch (e) { console.error("JSONパースに失敗:", e); result = null; // デフォルト値を設定 }
解決策: try-catch構文を使用してエラーを適切に処理し、エラー発生時の代替処理を実装します。
Javascriptfunction safeParseJson(jsonString, defaultValue = null) { try { return JSON.parse(jsonString); } catch (e) { console.error("JSONパースエラー:", e); return defaultValue; } }
まとめ
本記事では、JSON.parseが形式上問題ないのにエラーになる原因とその具体的な解決方法を解説しました。
- 余分な空白文字や改行はtrim()で除去
- 引用符の不一致は正規表現で修正
- 余分なカンマは正規表現で除去
- BOMの問題は事前に削除
- 特殊文字やエスケープシーケンスは適切にエスケープ
- 数値表現の問題は文字列として扱い後で変換
- 不完全なJSONデータはtry-catchで安全に処理
この記事を通して、JSON.parseのエラー問題を迅速に特定し、解決するための実践的なスキルを身につけることができたと思います。今後は、より複雑なJSONデータの処理や、パフォーマンスを考慮したJSONパースの最適化についても記事にする予定です。
参考資料
参考にした記事、ドキュメント、書籍などがあれば、必ず記載しましょう。
- MDN Web Docs - JSON.parse()
- JSON公式仕様
- Effective JavaScript - Item 52: JSON.parseを使う前に文字列を検証する
- JavaScript: The Good Parts - 第4章: JSON