JSON解析は地雷原です

画像



JSONは、(デ)シリアル化、ネットワーク共有、およびモバイル開発に関しては事実上の標準です。 しかし、JSONにどれだけ精通していますか? 私たちは皆、仕様を読んでテストを書き、必要に応じて人気のあるJSONライブラリをテストします。 JSONは多くの人が考えているように、JSONは理想的な形式であり、理想的な形式ではないことを示します。 同じように動作する2つのライブラリは見つかりませんでした。 さらに、主にJSONライブラリは時間とともに進化する仕様に基づいているため、極端なケースや悪意のあるペイロードがバグ、クラッシュ、およびDoSにつながる可能性があることがわかりました。



内容
1. JSON仕様

2. 解析テスト

2.1。 構造

2.2。 数字

2.3。 配列

2.4。 オブジェクト

2.5。

2.6。 RFC 7159の二重の価値

3. テストアーキテクチャ

4. テスト結果

4.1。 完全な結果

4.2。 Cパーサー

4.3。 Objective-Cパーサー

4.4。 Apple(NS)JSONSerialization

4.5。 フレディ(スイフト)

4.6。 Bash JSON.sh

4.7。 その他のパーサー

4.8。 JSONチェッカー

4.9。 正規表現

5. コンテンツの解析

6. STJSON

7. 結論

8. アプリケーション


1. JSON仕様



JSONは、Web開発とモバイル開発の両方で異種アプリケーション間でデータを交換するための共通語であるHTTPを介してデータを送信する際の事実上のシリアル化の標準です。



2001年、 Douglas Crockfordは短くてシンプルなJSON仕様を開発し、JSONの完全な文法を裏に印刷する名刺を作成しました。







ほとんどすべてのインターネットユーザーとプログラマーはJSONを使用しますが、JSONがどのように機能するかについて実際に同意しているのはごく少数です。 文法の簡潔さにより、多くの側面があいまいになります。 さらに、いくつかの仕様とその曖昧な解釈があります。



Crockford JSONをバージョン管理しないことに決めました



おそらく、私の最も意外な設計上の決定は、JSON番号バージョンの割り当てを拒否することでした。そのため、変更を加えるメカニズムはありません。 JSONにこだわっています。現在の形式が何であれ、それだけです。




さらに、JSONは少なくとも6つの異なるドキュメントで定義されています。



  1. 2002-json.orgおよび名刺。
  2. 2006- IETF RFC 4627は 、環境のapplication / json MIMEタイプを設定します。
  3. 2011- ECMAScript 262、セクション15.12
  4. 2013- ECMA 404 Tim Bray(RFC 7159エディター)によると、 ECMAはリリースを急いだ

    誰かがECMAワーキンググループに、IETFはクレイジーであり、インターネット全体の互換性と内訳を考慮せずにJSONを書き直そうとしていると語りました。 <...>これは、IETFによる監査に影響を与えた苦情とは関係ありません。
  5. 2014- IETF RFC 7158 「情報」の代わりに「標準トラック」仕様を作成します。 123などのスカラー(配列とオブジェクト以外)を使用でき、ECMAなどのルートレベルでtrueを使用できます。 キーの重複やUnicode文字列の破損など、失敗したソリューションの使用に対する注意。ただし、明示的に禁止されているわけではありません。
  6. 2014- IETF RFC 7159 RFC 7158のタイプミスを修正するために発行されました。これは2014年3月ではなく2013年3月の日付です。


明確性にもかかわらず、RFC 7159にはいくつかの前提が含まれており、多くの不十分な点が残されています。



特に、RFC 7159 、JSON開発の目標は「JavaScriptのサブセット」を作成することであると述べていますが、実際にはそうではありません。 たとえば、JSONでは、Unicode U+2028 LINE SEPARATOR



およびU+2029 PARAGRAPH SEPARATOR



のエスケープされていない行末文字を使用できます。 ただし、JavaScript仕様では、文字列値に行末文字( ECMA-262-7.8.4文字列リテラル )を含めることはできず、一般的にこれらの文字にはU+2028



およびU+2029



7.3行終端 記号 )が含まれるとU+2029



ます。 これら2つの文字はエスケープせずにJSON文字列で使用でき、JSでまったく暗示されていないという事実は、述べられた開発目標にもかかわらず、JSONはJavaScriptのサブセットではないことを示唆しています。



また、RFC 7159は、JSONパーサーが極端な数値、ゆがんだUnicode文字列、同じオブジェクト、または再帰の深さをどのように処理するかを明確にしていません。 いくつかのデッドロックは明らかに実現せずに残されていますが、他のデッドロックは矛盾するステートメントに苦しんでいます。



RFC 7159の不正確さを説明するために、テストJSONファイルのコレクションを作成し、特定のJSONパーサーがそれらを処理する方法を文書化しました。 以下では、特定のテストファイルを解析するかどうかを判断するのは必ずしも簡単ではないことがわかります。 私の研究では、すべてのパーサーの動作が異なり、これが深刻な互換性の問題につながる可能性があることがわかりました。



2.解析テスト



次に、パーサーの動作を確認するためのテストファイルの作成方法について説明し、いくつかの興味深いテストについて説明し、RFC 7159基準を満たすパーサーがファイルを受け入れるか拒否するか、または独自に決定するかを正当化します。



ファイル名は、予想される結果を示す文字で始まります。





また、パーサーのどのコンポーネントがテストされたかは、ファイルから明らかになります。



たとえば、 n_string_unescaped_tab.json



["09"]



が含まれます-これは、文字TAB 0x09



を含む文字列の配列で、JSON仕様に従ってエスケープする必要があります。 このファイルは文字列の解析をテストするため、名前には、 structure



array



またはobject



ではなくstring



が含まれobject



。 RFC 7159によると、これは無効な文字列値であるため、ファイル名にn



れています。



いくつかのパーサーではトップレベルのスカラー( "test"



)が許可されていないため、配列に文字列を埋め込んでいます( ["test"]



)。



JSONTestSuiteリポジトリには300以上のテストファイルがあります。



ほとんどの場合、私は仕様を読みながら手動でファイルを作成し、極端な状況とあいまいな点に注意を払っていました。 また、インターネット上にある外国のテストスイート(主にjson-test-suiteJSON Checker )の開発を使用しようとしましたが、それらのほとんどが基本的な状況のみをカバーしていることがわかりました。



最後に、 American Fuzzy Lopファジングソフトウェアを使用してJSONファイルを生成しました。 次に、1つの結果につながる冗長なテストを削除し、残りのテストの数を減らして、結果が得られる最小数の文字が得られるようにしました( セクション3を参照)。



2.1。 構造



スカラー-明らかに、123や「asd」などのスカラーを解析する必要があります。 実際には、多くの一般的なパーサーはまだRFC 4627を実装しており、単一の値を解析しません。 したがって、次のような基本的なテストがあります。



 y_structure_lonely_string.json "asd"
      
      





[123,]



{"a":1,}



などの末尾のコンマは文法の一部ではないため、このようなファイルはテストに合格しないはずですよね? しかし、実際には、RFC 7159ではパーサーが「拡張」( セクション9 )をサポートできるようになっていますが、それらについての説明はありません。 実際には、末尾のコンマは一般的な拡張子です。 これはJSON文法の一部ではないため、パーサーはそれらサポートする必要ないため、ファイル名はnで始まります。



 n_object_trailing_comma.json {"id":0,} n_object_several_trailing_commas.json {"id":0,,,,,}
      
      





コメントも文法の一部でありません。 Crockford それらを初期の仕様から削除しました。 しかし、これは別の一般的な拡張機能です。 一部のパーサーでは、 [1]//xxx



または組み込みの[1,/*xxx*/2]



を閉じるコメントを使用できます。



 y_string_comments.json ["a/*b*/c/*d//e"] n_object_trailing_comment.json {"a":"b"}/**/ n_structure_object_with_comment.json {"a":/*comment*/"b"}
      
      





オープン構造 。 テストは、開いている構造と閉じていない構造(またはその逆)がある場合のすべての状況をカバーします(例[



または[1,{,3]



。 明らかに、これは間違いであり、テストに合格するべきではありません。



 n_structure_object_unclosed_no_value.json {"": n_structure_object_followed_by_closing_object.json {}}
      
      





入れ子構造。 構造には、他の構造、配列、他の配列が含まれることがあります。 最初の要素は、人形[[[[[]]]]]



ように、最初の要素も配列などである配列にすることができます。 RFC 7159では、パーサーはネストの最大深度に制限を設定できます( セクション9 )。



いくつかのパーサーは深さを制限せず、ある時点で単純に落ちます。 たとえば、千文字[



を含む.jsonファイルを開くと、Xcodeはクラッシュします。 おそらく、深度制限がJSON構文セレクターに実装されていないためです。



 $ python -c "print('['*100000)" > ~/x.json $ ./Xcode ~/x.json Segmentation fault: 11
      
      





スペース。 RFC 7159の文法では、品質として0x20



(スペース)、 0x09



(タブ)、 0x0A



(改行)、および0x0D



(キャリッジリターン)を使用できます。 「構造文字」の前後にスペースを入れることができます[]{}:,



。 したがって、 20[090A]0D



はテストに合格します。 逆に、入力フォーム0x0C



または[E281A0]



-単語コネクタU+2060 WORD JOINER



UTF-8指定など、明示的に許可されていないあらゆる種類のスペースを含めると、ファイルはテストに合格しません。



 n_structure_whitespace_formfeed.json [0C] n_structure_whitespace_U+2060_word_joiner.json [E281A0] n_structure_no_data.json
      
      





2.2。 数字



NaNおよびInfinity。 NaN



Infinity



などの特別な数値を記述する行は、JSON文法の一部ではありません。 しかし、一部のパーサーはそれらを「拡張」と見なして受け入れます( セクション9 )。 テストファイルでは、否定形式-NaN



および-Infinity



もチェックされます。



 n_number_NaN.json [NaN] n_number_minus_infinity.json [-Infinity]
      
      





16進数 -RFC 7159では使用できません。 テストには0xFF



などの数値が含まれます。このようなファイルは解析しないでください。



 n_number_hex_2_digits.json [0x42]
      
      





範囲と精度 -膨大な数の数字はどうですか? RFC 7159によると、「JSONパーサーはJSON文法に対応するすべての種類のテキストを受け入れなければなりません」( 第9章 )。 しかし、同じ段落には、「実装によって数値の範囲と精度が制限される可能性があります」と書かれています。 そのため、パーサーが1e9999



0.0000000000000000000000000000001



などの値に遭遇したときにエラーをスローできるかどうかはわかりません。



 y_number_very_big_negative_int.json [-237462374673276894279832(...)
      
      





指数概念 -それらを解析することは驚くほど難しいタスクです(結果の章を参照)。 有効なオプション( [0E0]



[0e+1]



)、および無効なオプション( [1.0e+]



[0E]



および[1eE2]



)があります。



 n_number_0_capital_E+.json [0E+] n_number_.2e-3.json [.2e-3] y_number_double_huge_neg_exp.json [123.456e-789]
      
      





2.3。 配列



配列に関連する極端な状況のほとんどは、開閉の制限とネストの制限に関する問題です。 それらについては、セクション2.1(構造)で説明します。 テストは[[]



および[[[]]]



に合格しますが、 ]



または[[]]]



は合格しません。



 n_array_comma_and_number.json [,1] n_array_colon_instead_of_comma.json ["": 1] n_array_unclosed_with_new_lines.json [1,0A10A,1
      
      





2.4。 オブジェクト



重複キーRFC 7159のセクション4には、 「エンティティ内に一意の名前が必要です」とあります。 これにより、1つのキーが複数回現れるオブジェクトの解析{"a":1,"a":2}



防ぐことはできませんが、パーサーはそのような場合に何をするかを決定できます。 セクション4では、「[一部の]実装がオブジェクト解析中にエラーまたは誤動作を報告する」ことまで言及していますが、解析の誤動作がRFCの規定に準拠しているかどうかを指定せずに、特に次のように記述しています。 「。



このような特殊なケースのバリエーションには、同じキーが含まれます。同じ値{"a":1,"a":1}



だけでなく、文字列の比較方法に依存するキーまたは値も含まれます。 たとえば、キーはバイナリで異なる場合がありますが、Inicode NFC正規化に従って同等: {"C3A9:"NFC","65CC81":"NFD"}



、ここでは両方のキーが"é "を示します。 {"a":0,"a":-0}







 y_object_empty_key.json {"":0} y_object_duplicated_key_and_value.json {"a":"b","a":"b"} n_object_double_colon.json {"x"::"b"} n_object_key_with_single_quotes.json {key: 'value'} n_object_missing_key.json {:"b"} n_object_non_string_key.json {1:1}
      
      





2.5。 行



ファイルのエンコード。 「JSONテキストはUTF-8、UTF-16、またはUTF-32エンコーディングである必要があります。 デフォルトはUTF-8”( セクション8.1 )。

したがって、テストに合格するには、3つのエンコーディングのいずれかが必要です。 UTF-16およびUTF-32のテキストには、高バージョンと低バージョンも含める必要があります。



障害テストには、ISO-Latin-1でエンコードされた文字列が含まれます。



 y_string_utf16.json FFFE[00"00E900"00]00 n_string_iso_latin_1.json ["E9"]
      
      





バイトオーダーマーク セクション8.1には「実装はJSONテキストの先頭にバイトシーケンスマーカーを追加すべきではありません」と記載されていますが、「実装...マーカーの存在を無視し、エラーとして扱わない場合があります。」



障害テストには、UTF-8でエンコードされたマークのみが含まれ、他のコンテンツは含まれません。 結果が実装固有のテストには、UTF-8文字列を含むUTF-8 BOM、UTF-16文字列を含むUTF-8 BOM、UTF-8文字列を含むUTF-16 BOMが含まれます。



 n_structure_UTF8_BOM_no_data.json EFBBBF n_structure_incomplete_UTF8_BOM.json EFBB{} i_structure_UTF-8_BOM_empty_object.json EFBBBF{}
      
      





制御文字は分離し、 U+0000



としてU+001F



として定義する必要があります( セクション7 )。 これには、他の制御文字定義の一部である可能性がある0x7F DEL文字は含まれません(セクション4.6、Bash JSON.shを参照)。 したがって、テストは["7F"]



合格する必要があります。



 n_string_unescaped_ctrl_char.json ["a\09a"] y_string_unescaped_char_delete.json ["7F"] n_string_escape_x.json ["\x00"]
      
      





シールド。 「すべての文字をエスケープできます」( セクション7 )、たとえば、\ uXXXX。 ただし、引用符、バックスラッシュ、エスケープ文字の一部はエスケープする必要があります。 失敗したテストには、エスケープ値のない文字やエスケープが不完全な文字のエスケープが含まれます。 例: ["\"]



["\



[\







 y_string_allowed_escapes.json ["\"\\/\b\f\n\r\t"] n_structure_bad_escape.json ["\
      
      





エスケープ文字を使用して、Basic Multilingual Plane(BMP)( \u005C



)でコードポイントを表すことができます。 成功したテストにはゼロ文字\u0000



含まれ、Cのパーサーで問題が発生する可能性があります。失敗したテストには、大文字のU \U005C



、16進数以外のエスケープ値\u123Z



、不完全なエスケープ値\u123



ます。



 y_string_backslash_and_u_escaped_zero.json ["\u0000"] n_string_invalid_unicode_escape.json ["\uqqqq"] n_string_incomplete_escaped_character.json ["\u00A"]
      
      





エスケープされた非Unicode文字



BMPの外側のコードポイントは、UTF-16でエンコードされたシールドされたサロゲートによって表されます。 +1D11E



\uD834\uDD1E



ます。 JSON文法の観点から有効であるため、成功したテストには単一の代理が含まれます。 RFC 7159 の3984の誤植により 、ユニコード文字( \uDEAD



)ではない、またはU+FDD0



からU+FDD0



までの非文字ではない、文法的に正しいエスケープコードポイントの問題がU+10FFFE







同時に、拡張バッカスナウアフォーム(ABNF、 拡張バッカスナウアフォーム )では、非Unicodeコードポイントの使用が許可されておらず(セクション7)、Unicode準拠が必要です(セクション1)。



編集者は、文法を制限すべきではなく、パーサーの動作の「予測不可能性」( RFC 7159、セクション8.2 )についてユーザーに警告するだけで十分であると判断しました。 言い換えれば、パーサーはuシールドされた非文字を解析しなければなりませんが、結果は予測不能です。 このような場合、ファイル名はi_



プレフィックスで始まります(実装に依存)。 Unicode標準に従って、無効なコードポイントは、置換文字U+FFFD REPLACEMENT CHARACTER



置き換える必要があります。 すでにUnicodeの複雑さに遭遇している場合、置換はオプションであり、さまざまな方法で実行できることに驚くことはありません( ユニコードPR#121:置換文字の推奨テクニックを参照)。 したがって、一部のパーサーは置換文字を使用しますが、他のパーサーはエスケープされたフォームを残すか、非Unicode文字を生成します( セクション5-コンテンツの解析を参照)。



 y_string_accepted_surrogate_pair.json ["\uD801\udc37"] n_string_incomplete_escaped_character.json ["\u00A"] i_string_incomplete_surrogates_escape_valid.json ["\uD800\uD800\n"] i_string_lone_second_surrogate.json ["\uDFAA"] i_string_1st_valid_surrogate_2nd_invalid.json ["\uD888\u1234"] i_string_inverted_surrogates_U+1D11E.json ["\uDd1e\uD834"]
      
      





生の非Unicode文字



前のセクションでは、文字列( \uDEAD



)で発生する非Unicodeコードポイントについて説明しました。 これらのポイントはuシールド形式の有効なUnicodeですが、Unicode文字にデコードされません。



パーサーは、Unicode文字をエンコードしない通常のバイトも処理する必要があります。 たとえば、UTF-8では、FFバイトはUnicode文字ではありません。 したがって、FFを含む文字列値はUTF-8でエンコードされた文字列ではありません。 この場合、「文字列値は0以上のUnicode文字のシーケンス」( RFC 7159、セクション1 )および「JSONテキストはUnicodeエンコードで表現する必要がある」( RFC 7159であるため、パーサーは単に解析を拒否する必要があります、セクション8.1 )。



 y_string_utf8.json ["€?"] n_string_invalid_utf-8.json ["FF"] n_array_invalid_utf8.json [FF]
      
      





RFC 7159のあいまいさ



調査した特定のケースに加えて、パーサーがRFC 7159の要件に準拠しているかどうかを確立することは、 セクション9で述べられている理由によりほとんど不可能です。



JSONパーサーは、JSON文法に一致するすべてのテキストを受け入れなければなりません。 JSONパーサーは、JSON以外のフォームまたは拡張機能を受け入れる場合があります。




これまでのところ、すべてが明確です。 すべての文法的に正しい入力を解析する必要があり、パーサーは他のコンテンツを受け入れるかどうかを自分で決定できます。



実装により制限される場合があります。



  • 受信したテキストのサイズ。
  • 最大のネストの深さ;
  • 数値の範囲と精度;
  • 文字列値とその文字セットの長さ。




これらの制限はすべて(文字の例外を除き)合理的に聞こえますが、前の引用の「MUST」という言葉と矛盾しています。 RFC 2119はその意味を非常に明確に説明しています。



する必要があります。 この用語は、「必須」または「する必要がある」のように、必須の仕様要件を意味します。




RFC 7159は制限を許可していますが、最小要件を指定していません。 したがって、技術的には、3文字より長い文字列を解析できないパーサーは、RFC 7159に準拠しています。



さらに、RFC 7159のセクション9では、パーサーは制限を明確に文書化するか、カスタム構成の使用を許可する必要があります。 ただし、これらの構成では互換性の問題が発生する可能性があるため、最小要件を考慮することをお勧めします。



許容される制限の背景に対するこのような特異性の欠如により、パーサーがRFC 7159に一致するかどうかを確認することはほとんど不可能になります。



3.テストアーキテクチャ



パーサーの動作に関係なく、パーサーの実際の動作を確認したかったのです。 そのため、複数のJSONパーサーを選択し、テストファイルをフィードできるようにすべてを構成しました。



私はCocoa開発者なので、ほとんどのパーサーはSwiftとObjective-Cで書かれています。 しかし、C、Python、Ruby、R、Lua、Perl、Bash、およびRustには非常にarbitrarily意的に選択されたパーサーがあります。 基本的に、年齢と人気が多様な言語をカバーしようとしました。



一部のパーサーでは、制限を強化または制限したり、Unicodeサポートを構成したり、特定の拡張機能を使用したりできます。 RFC 7159の最も厳密な解釈にできるだけ近い動作をするようにパーサーを常に構成したかったのです。



run_tests.py



Pythonスクリプトrun_tests.py



すべてのテストファイルを各パーサー(またはファイルが引数として渡される場合は単一のテスト)で実行しました。 通常、パーサーはラップされ、成功した場合は0を返し、解析が失敗した場合は1を返しました。 パーサーが落ちるための個別のステータスと、5秒のタイムアウトが提供されました。 基本的に、JSONパーサーをJSONバリデーターに変換しました。



run_tests.py



は、各テストの戻り値と予想される結果を比較し、ファイル名のプレフィックスに反映しました。 それらが一致しなかった場合、または接頭辞がi



(実装依存)であった場合、 run_tests.py



は特定の形式の行をログにresults/logs.txt



results/logs.txt



):



 Python 2.7.10 SHOULD_HAVE_FAILED n_number_infinity.json
      
      









次に、 run_tests.py



がログを読み取り、結果を含むHTMLテーブルを生成します( results/parsing.html



)。



各行には、いずれかのファイルの結果が含まれています。 パーサーは列で表示されます。 異なる結果のために、異なるセル塗りつぶしの色が提供されます。







テストは結果でソートされます。 これにより、同様の結果を簡単に見つけて、冗長な結果を削除できます。







4.結果とコメント



4.1。 完全な結果



完全なテスト結果は、 seriot.ch / json / parsing.htmlにあります。 テストは同様の結果でソートされます。 run_tests.py



は、「プルーニングされた結果」を表示できるオプションがありますrun_tests.py



テストスイートで同じ結果が得られた場合、最初のテストのみが保存されます。 短縮データを含むファイルは、 www.seriot.ch / json / parsing_pruned.htmlから入手できます。



制御されない入力を解析するとプロセス全体が危険にさらされるため、ドロップ(赤)は最も深刻な問題です。 「予想される正常な実行」テスト(茶色)も非常に危険です。制御されていない入力データは、ドキュメント全体の解析を妨げる可能性があります。 「予想される実行の失敗」テスト(黄色)はそれほど危険ではありません。 彼らは、乾くことができない「拡張」について話します。 したがって、パーサーがこれらの「拡張」を解析できない別のものに置き換えられるまで、すべてが機能します。







さらに、最も注目すべき結果を確認し、コメントします。



4.2。 Cパーサー



5つのCパーサーを選択しました。





簡単な比較表:







詳細は、完全な結果表に記載されています。



4.3。 Objective-Cパーサー



特にAppleがiOS 5より前にNSJSONSerializationをリリースしなかったため、iOS開発の夜明けに非常に人気のあった3つのObjective-Cパーサーを選択しました。 3つのパーサーはすべて、多くのアプリケーションの開発に使用されていたため、テストするのが面白かったです。





簡単な比較表:







SBJSONはNSJSONSerializationの出現を生き延びましたが、まだサポートされており、CocoaPods経由でダウンロードできます。 そのため、 アプリケーション#219では 、解析が["FF"]のようなUTF-8行でない場合にクラッシュを登録しました。



 *** Assertion failure in -[SBJson4Parser parserFound:isValue:], SBJson4Parser.m:150 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: obj' *** First throw call stack: ( 0 CoreFoundation 0x00007fff95f4b4f2 __exceptionPreprocess + 178 1 libobjc.A.dylib 0x00007fff9783bf7e objc_exception_throw + 48 2 CoreFoundation 0x00007fff95f501ca +[NSException raise:format:arguments:] + 106 3 Foundation 0x00007fff9ce86856 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198 4 test_SBJSON 0x00000001000067e5 -[SBJson4Parser parserFound:isValue:] + 309 5 test_SBJSON 0x00000001000073f3 -[SBJson4Parser parserFoundString:] + 67 6 test_SBJSON 0x0000000100004289 -[SBJson4StreamParser parse:] + 2377 7 test_SBJSON 0x0000000100007989 -[SBJson4Parser parse:] + 73 8 test_SBJSON 0x0000000100005d0d main + 221 9 libdyld.dylib 0x00007fff929ea5ad start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException
      
      





4.4. Apple (NS)JSONSerialization



developer.apple.com/reference/foundation/nsjsonserialization



NSJSONSerialization iOS 5, JSON- OS X iOS. Objective-C Swift: NSJSONSerialization.swift . Swift 3 NS .







JSONSerialization :





JSONSerialization :





, , . .







JSON-, JSON-. , , JSONSerialization Double.nan



. , NaN



JSON, JSONSerialization , .



 do { let a = [Double.nan] let data = try JSONSerialization.data(withJSONObject: a, options: []) } catch let e { } SIGABRT *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid number value (NaN) in JSON write'
      
      





4.5. Freddy (Swift)



Freddy (https://github.com/bignerdranch/Freddy) — JSON-, Swift 3. «», GitHub- Swift JSON-, Apple JSONSerialization JSON- -.



Freddy , Cocoa- Swift Swift- JSON- (Array, Dictionary, Double, Int, String, Bool Null).



Freddy 2016- , . , [1



, {"a":



, " ". #199 , !



, "0e1"



, #198 , .



18 Freddy ["



\



. #206 .



Freddy:







4.6. Bash JSON.sh



github.com/dominictarr/JSON.sh , 12 2016 .



Bash- , , RFC 7159, . Bash JSON , .



:cntlr:



. [\x00-\x1F\x7F]



. JSON 0x7F DEL



.



  00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' 28 ( 29 ) 2a * 2b + 2c , 2d — 2e . 2f / 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ? 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _ 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del
      
      





JSON.sh ["7F"]



. . JSON.sh 10 000 [. .



 $ python -c "print('['*100000)" | ./JSON.sh ./JSON.sh: line 206: 40694 Done tokenize 40695 Segmentation fault: 11 | parse
      
      





4.7。



C / Objective-C Swift, . . , , , .







:





Java-, , :





JSON- Python NaN



-Infinity



. , parse_constant , , . , .



 def f_parse_constant(o): raise ValueError o = json.loads(data, parse_constant=f_parse_constant)
      
      





4.8. JSON Checker



JSON- JSON- . JSON, .



, JSON. — JSON-.



JSON_Checker. www.json.org/JSON_checker , ():



JSON_Checker — pushdown automaton , JSON-. . JSON_Checker JSON-.




JSON_Checker , , JSON- .



, JSON_Checker , . , [1.]



, [0.e1]



, JSON.



, JSON_Checker [0e1]



, JSON-. , - 0e1



.



JSON_Checker pushdown automaton , , , .







1: 0e1 . ZE



, 0



, E1



e



E



. , .



2: [1.] . , 0.



, . , 1.



, .



JSON_Checker FR



, . , FR



F0



frac0



. 1.



.







(Obj-C TouchJSON, PHP, R rjson, Rust json-rust, Bash JSON.sh, C jsmn Lua dkjson) [1.]



. JSON_Checker? , json.org.



4.9. 正規表現



JSON? , , . , , .



StackOverflow Ruby JSON :



 JSON_VALIDATOR_RE = /( # define subtypes and build up the json syntax, BNF-grammar-style # The {0} is a hack to simply define them as named groups here but not match on them yet # I added some atomic grouping to prevent catastrophic backtracking on invalid inputs (?<number> -?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?){0} (?<boolean> true | false | null ){0} (?<string> " (?>[^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " ){0} (?<array> \[ (?> \g<json> (?: , \g<json> )* )? \s* \] ){0} (?<pair> \s* \g<string> \s* : \g<json> ){0} (?<object> \{ (?> \g<pair> (?: , \g<pair> )* )? \s* \} ){0} (?<json> \s* (?> \g<number> | \g<boolean> | \g<string> | \g<array> | \g<object> ) \s* ){0} ) \A \g<json> \Z /uix
      
      





JSON, :





( JSON-):





5.



RFC 7159 ( 9) :



JSON- JSON- .




, JSON-, .



, u- Unicode- ( "\uDEAD"



), ? - ? RFC 7159 .



0.00000000000000000000001



-0



? , ? RFC 7159 0 –0. , .



, ( {"a":1,"a":2}



)? ( {"a":1,"a":1}



)? ? Unicode-, NFC? RFC .



. — (, , JSON- ).



, . , . , . (log statements) / .



. « ».









オブジェクト











6. STJSON



STJSON — JSON-, Swift 3 600+ . , , .



github.com/nst/STJSON



STJSON API :



 var p = STJSONParser(data: data) do { let o = try p.parse() print(o) } catch let e { print(e) }
      
      





STJSON :



 var p = STJSON(data:data, maxParserDepth:1024, options:[.useUnicodeReplacementCharacter])
      
      





: y_string_utf16.json



. , , , STJSON UTF-8 , , , , . STJSON , UTF-16 UTF-32.



7.



JSON — , . , :





, , json_checker.c json.org JSON [0e1]



( 4.24 ), , , . ( ) , , , .



JSON- ( 6 ), JSON- RFC 7159. , pull request'.



:





, «» HTML, CSS JSON «» PHP JavaScript . , , , , - , . .



8.



  1. seriot.ch/json/parsing.html , 4 .
  2. seriot.ch/json/transform.html , 6 .
  3. JSON github.com/nst/JSONTestSuite , .
  4. STJSON github.com/nst/STJSON , , Swift 3.



All Articles