根据 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
。您会发现出于同样的原因,它jq
也会重新格式化1.0
为1
、1e2
as 100
、INF
as等。1.7976931348623157e+308
然而,JSON 是一种相对简单的文件格式,可以使用 perl 正则表达式等手动可靠地处理。
要在除对象键之外的所有字符串中的\
每个字符串之前添加回s,您可以执行以下操作:/
jq... |
perl -0777 -pe '
s{"(?:\\.|.)*?"(\s*:)?}{
$1 ? $& : $& =~ s{/}{\\/}gr
}ge'
即使您有嵌入"
s 和\
s 的字符串(例如{"key": "//\"//\\"}
),它也应该正常工作。
作为 的替代方案jq
,您可以使用 JSON::PPperl
模块,该模块可以被告知转义斜杠(尽管会出现在所有字符串中):
$ json_pp -json_opt escape_slash < your-file
{"proto:\/\/some\/path":"\/\/some\/path"}
如果您已经熟悉perl
,那么学习曲线将不会比学习jq
语法那么陡峭。
在任何情况下,虽然 JSON 格式允许/
将 s 转义为\/
(或\u002f
类似任何字符)但不需要。根据我在网上读到的内容,这是允许的,因此可以通过编写HTML 标签来嵌入包含</
在 HTML 标签中的 JSON 字符串。这就是为什么一些 JSON 编码器对它们进行编码,因为这使其更便携。但如果该 JSON 不打算像 HTML 那样嵌入,那么它可能并不重要。如果是的话,您可能希望在任何地方都使用这种编码,包括在对象键中。<script>
"<\/whatever"
\/
/
答案2
我假设某些不知道需要在 JSON 中编码字符串的进程已经插入了他们认为需要存储的文字字符串,但没有对其进行编码。由于反斜杠是不需要转义的转义字符,并且由于没有反斜杠本身转义文字反斜杠,因此当jq
用于提取和解码字符串或出于其他原因处理文档时,它们似乎“消失”。
简而言之,向前斜杠不必转义(转义它们实际上是无操作),但如果您想将反斜杠保留为文字反斜杠,则需要转义反斜杠。
以下将递归地将文档中所有字符串值中的每个更改/
为\\/
(这是您在 JSON 字符串中编写的方式)。\/
请记住,当jq
表达式处理数据时,jq
解析器已经删除了反斜杠。
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"
}