jqを使用して、JSON文字列値からエスケープされたスラッシュを保持します。

jqを使用して、JSON文字列値からエスケープされたスラッシュを保持します。

JSON仕様によると、スラッシュは使用できません。持つバックスラッシュで逃げるが、彼らはできるはい。
互換性の理由から、文字列値(キーの内部ではない)内のすべてのスラッシュがエスケープされるJSONファイルがあります。

{
  "proto://some/path": "\/\/some\/path"
}

ただし、jq次のバックスラッシュは自動的に削除されます。

$ echo '{"proto://some/path":"\/\/some\/path"}' | jq -c .
{"proto://some/path":"//some/path"}

出力が必要です。{"proto://some/path":"\/\/some\/path"}

jq文字列値を変更せずにバックスラッシュを維持する方法を教えてください。
または、これらのバックスラッシュを再追加する方法はありますか?値のみ体験後はjq

答え1

できれば驚きます。jq入力をデコードし、操作を実行し、結果オブジェクトをjsonにエンコードします。エンコードおよび出力の場合、出力はJSONエンコード文字列であり、s\の前のs情報は/長い間失われました。もしそれらが/もともと書かれていたら、同じことが起こります\u002f。同じ理由で、as、asなどでjq再フォーマットされることがわかります。1.011e2100INF1.7976931348623157e+308

ただし、JSONはPerl正規表現などを使用して手動で安定して処理できる比較的単純なファイル形式です。

オブジェクト key を除くすべての文字列の\すべての文字列の前に s を再度追加するには、次のようにします。/

jq... |
  perl -0777 -pe '
    s{"(?:\\.|.)*?"(\s*:)?}{
      $1 ? $& : $& =~ s{/}{\\/}gr
    }ge'

"sとsを含む文字列があっても正常に動作します\(例:)。{"key": "//\"//\\"}

あるいは、スラッシュをエスケープするように指示できるjqJSON :: PPperlモジュールを使用できます(すべての文字列に表示されますが)。

$ json_pp -json_opt escape_slash < your-file
{"proto:\/\/some\/path":"\/\/some\/path"}

すでに慣れている場合は、学習曲線が構文学習ほど急になりませんperljq

いずれにせよ、JSON形式を使用すると/sをエスケープできますが\/(または\u002fすべての文字と同様に)必須ではありません。私がオンラインで読んだことによると、これは許可されているので、HTML</タグを作成してHTMLタグに埋め込まれたJSON文字列を挿入できます。これが一部のJSONエンコーダがそれをエンコードする理由です。これは移植性を高めるためです。しかし、JSONがHTMLのように含まれることを意図していない場合は、おそらく重要ではありません。もしそうなら、オブジェクトキーを含むどこでもこのエンコーディングを使用したいと思います。<script>"<\/whatever"\//

答え2

JSONでエンコードする必要がある文字列を知らないいくつかのプロセスが保存する必要があると思うリテラル文字列を挿入しましたが、エンコードしなかったとします。バックスラッシュはエスケープする必要のないエスケープ文字であり、バックスラッシュ自体がリテラルバックスラッシュをエスケープしないため、文字列を抽出してデコードしたり、他jqの理由で文書を処理したりするときに「消える」ようです。

要するに、今後スラッシュはエスケープする必要はありませんが(エスケープ処理は事実上何もしません)、バックスラッシュを文字通りバックスラッシュに保つにはバックスラッシュをエスケープする必要があります。

以下は、ドキュメント内のすべての文字列値をそれぞれ次のように再帰的に変更します/\\/これはJSON文字列に書き込む方法です)。式がデータを処理するときにパーサーがバックスラッシュを削除したこと\/を覚えておいてください。jqjq

jq 'walk(if type == "string" then gsub("/"; "\\/") else . end)' file

与えられたサンプル文書に対して以下が生成される。

{
  "proto://some/path": "\\/\\/some\\/path"
}

変更された文書からエンコードされた文字列値を抽出してデコードすると、次のようになります\/\/some\/path

$ jq 'walk(if type == "string" then gsub("/"; "\\/") else . end)' file | jq -r '."proto://some/path"'
\/\/some\/path

最初から作成すると、次のJSONドキュメントが生成されます。

$ jq -n --arg 'proto://some/path' '\/\/some\/path' '$ARGS.named'
{
  "proto://some/path": "\\/\\/some\\/path"
}

関連情報