我需要以一种不同寻常的格式为客户输出一些JSON。我的应用程序是用Rails 5编写的。
所需的JSON:
{
"key": "\/Date(0000000000000)\/"
}
时间戳值需要在字符串的开头和结尾都有\/
。据我所知,这似乎是.NET services中常用的格式。我试图让斜线正确输出。
我通过单个控制器操作将问题简化为vanilla Rails 5应用程序。到目前为止,我能想到的逃逸的所有排列都失败了。
def index
render json: {
a: '\/Date(0000000000000)\/',
b: "\/Date(0000000000000)\/",
c: '\\/Date(0000000000000)\\/',
d: "\\/Date(0000000000000)\\/"
}
end
其中输出以下内容:
{
"a": "\\/Date(0000000000000)\\/",
"b": "/Date(0000000000000)/",
"c": "\\/Date(0000000000000)\\/",
"d": "\\/Date(0000000000000)\\/"
}
为了便于讨论,假设格式无法更改,因为它是由第三方控制的。
我已将测试应用程序上传到Github以演示此问题。 https://github.com/gregawoods/test_app_ignore_me
答案 0 :(得分:11)
在与同事进行一些头脑风暴之后(感谢@TheZanke),我们找到了一个可以使用本机Rails JSON输出的解决方案。
警告:此代码会覆盖ActiveSupport中的某些核心行为。使用风险自负,并进行明智的单元测试!
我们将其跟踪到ActiveSupport中的JSON编码。所有字符串最终都通过ActiveSupport::JSON.encode
进行编码。我们需要找到一种方法来短路逻辑并简单地返回未编码的字符串。
首先,我们扩展了找到here的EscapedString#to_json
方法。
module EscapedStringExtension
def to_json(*)
if starts_with?('noencode:')
"\"#{self}\"".gsub('noencode:', '')
else
super
end
end
end
module ActiveSupport::JSON::Encoding
class JSONGemEncoder
class EscapedString
prepend EscapedStringExtension
end
end
end
然后在控制器中我们向json哈希添加一个noencode:
标志。这告诉我们的to_json
版本不要进行任何其他编码。
def index
render json: {
a: '\/Date(0000000000000)\/',
b: 'noencode:\/Date(0000000000000)\/',
}
end
呈现的输出显示b
为我们提供了我们想要的内容,而a
保留了标准行为。
$ curl http://localhost:3000/sales/index.json
{"a":"\\/Date(0000000000000)\\/","b":"\/Date(0000000000000)\/"}
答案 1 :(得分:6)
默想:
Ruby在双引号和单引号字符串中处理相同的正斜杠。
"/" # => "/"
'/' # => "/"
在双引号字符串"\/"
中表示\
正在转义以下字符。由于/
没有转义的等价物,因此会产生一个正斜杠:
"\/" # => "/"
在所有情况下的单引号字符串中,只有一个表示后面的斜杠后跟字符的字面值。这种情况就是你想要代表一个反斜杠:
'\/' # => "\\/"
"\\/" # => "\\/"
'\\/' # => "\\/"
学习这是处理语言中字符串最令人困惑的部分之一,这并不仅限于Ruby,它是编程初期的一些东西。
了解以上内容:
require 'json'
puts JSON[{ "key": "\/value\/" }]
puts JSON[{ "key": '/value/' }]
puts JSON[{ "key": '\/value\/' }]
# >> {"key":"/value/"}
# >> {"key":"/value/"}
# >> {"key":"\\/value\\/"}
您应该能够更好地了解您在结果和上面的JSON输出中看到的内容。
我认为这个规则最初是为C创建的,所以" Escape sequences in C"可能有所帮助。
答案 2 :(得分:0)
嗨,我认为这是最简单的方式
.gsub("/",'//').gsub('\/','')
表示输入{:key=>"\\/Date(0000000000000)\\/"}
(已打印)
第一个gsub会{"key":"\\//Date(0000000000000)\\//"}
第二个会帮你
{"key":"\/Date(0000000000000)\/"}
根据需要