为什么ruby的JSON解析器会吃掉我的反斜杠?

时间:2016-05-19 16:07:48

标签: ruby regex escaping backslash

以下JSON格式的示例包含一个反斜杠,如果我运行JSON.load,则反斜杠会消失:

JSON.load('{ "88694": { "regex": ".*?\. (CVE-2015-46055)" } }')
# => {"88694"=>{ "regex"=>".*?. (CVE-2015-46055)"}}

如何保留反斜杠?

我的目标是拥有这个结构,每当我需要时,读取文件,将JSON加载到Hash中,并搜索那些正则表达式。

更新1

这是我想要的一个例子。

irb> "stack.overflow"[/.*?\./]
=> "stack."

无法将正则表达式从JSON传递到我的字符串,以便抓住" ",因为&# 34; \"消失。

1 个答案:

答案 0 :(得分:3)

str = '{ "88694": { "regex": ".*?\. (CVE-2015-46055)" } }'
  #=> "{ \"88694\": { \"regex\": \".*?\\. (CVE-2015-46055)\" } }"

str.chars
  #=> ["{", " ", "\"", "8", "8", "6", "9", "4", "\"", ":", " ", "{", " ",
  #   "\"", "r", "e", "g", "e", "x", "\"", ":", " ", "\"", ".", "*", "?",
  #   "\\", ".",
  #   ~~~   ~~                                        
  #   " ", "(",..., "}", " ", "}"]

这告诉我们str确实包含一个反斜杠字符,后跟一个句点。原因是str用单引号括起来。如果\.用双引号括起来,则str只会被视为转义期:

 "{ '88694': { 'regex': '.*?\. (CVE-2015-46055)' } }".chars[25,3]
   #=> ["?", ".", " "] 

str的返回值将单引号字符串转换为双引号字符串:

"{ \"88694\": { \"regex\": \".*?\\. (CVE-2015-46055)\" } }"

\\是一个反斜杠字符,后跟一个句点。使用双引号,现在可以转义句点,但不会有反斜杠,只有退格符。

现在让我们添加另一个反斜杠,看看会发生什么:

str1 = '{ "88694": { "regex": ".*?\\. (CVE-2015-46055)" } }' 
str1.chars == str.chars
  #=> true

结果是一样的。这是因为单引号支持转义序列\\(单反斜杠)(并且只支持另一个:\' [单引号])。

现在让我们添加第三个反斜杠:

str2 = '{ "88694": { "regex": ".*?\\\. (CVE-2015-46055)" } }'   
str2.chars
  #=> ["{", " ", "\"", "8", "8", "6", "9", "4", "\"", ":", " ", "{", " ",
  #   "\"", "r", "e", "g", "e", "x", "\"", ":", " ", "\"", ".", "*", "?",
  #   "\\", "\\", ".",
  #   ~~~~  ~~~~  ~~~                                        
  #   " ", "(",..., "}", " ", "}"]

惊讶? \\生成一个反斜杠字符(单引号中的转义反斜杠),\个产品的第二个反斜杠字符(单引号中的反斜杠)和.是一个单引号的句点。

我们获得:

s = {"88694"=>{"regex"=>".*?\\. (CVE-2015-46055)"}.to_json

JSON.parse(str)
  #=> {"88694"=>{"regex"=>".*?. (CVE-2015-46055)"}} 
JSON.parse(str1)
  #=> {"88694"=>{"regex"=>".*?. (CVE-2015-46055)"}} 
JSON.parse(str2)
  #=> {"88694"=>{"regex"=>".*?\\. (CVE-2015-46055)"}} 

str2是我们想要的,如

JSON.parse(str2)["88694"]["regex"].chars[2,4]   
  #=> ["?", "\\", ".", " "] 

我们也可以倒退:

js = {"88694"=>{"regex"=>".*?\\. (CVE-2015-46055)"}}.to_json
  #=> "{\"88694\":{\"regex\":\".*?\\\\. (CVE-2015-46055)\"}}" 

'{"88694":{"regex":".*?\\\. (CVE-2015-46055)"}}' == js
  #=> true

在删除引用子字符串之外的所有空格后,此字符串与str2相同。

看起来JSON将两个连续的反斜杠字符视为一个反斜杠字符。请参阅@ Jordan的评论。

也许读者可以详细说明JSON在这里做了什么。