我在Postgresql数据库的jsonb列中有一个像这样的字符串:
"{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"
现在我想使用正则表达式使它看起来像这样:
[{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},
{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},
{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}
]
我正在尝试使用正则表达式拆分的方法来完成任务。但是,我仍然无法弄清楚如何只分割字符串中右大括号后面的逗号。 我能想到的就是用ruby中的扫描方法测试它,如下所示:
test = "{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"
result = test.scan(/\"},/)
=> result = ["\"},", "\"},"]
看起来我正走在正确的轨道上,但我被困在这里。任何建议将不胜感激。
更新 感谢Tinman先生您的深思熟虑的解释。我将数据库更改回hstore,并在将数据传递到后端之前使用JSON.stringify。在这里和那里有一些扭曲,我终于得到你想要的哈希,如你所说:
{"monday"=>{"start_time"=>9, "end_time"=>10.5}, "tuesday"=>{"start_time"=>8.5, "end_time"=>10}, "wednesday"=>{"start_time"=>8.5, "end_time"=>10}}
。但是,在将其保存到数据库之后,散列的所有值都被序列化为字符串:
{
"monday" => "{\"start_time\"=>9, \"end_time\"=>10.5}",
"tuesday" => "{\"start_time\"=>7, \"end_time\"=>8.5}",
"wednesday" => "{\"start_time\"=>7, \"end_time\"=>8.5}"
}
我知道我可以使用eval将它们转换回哈希值。但是,有没有什么方法可以将这些值保存为数据库中的哈希值,或者因为Hstore机制而无法将其保存?
答案 0 :(得分:1)
看起来您尝试创建自己的JSON序列化程序,而不是使用Ruby附带的序列化程序。或者,也许你没有意识到JSON是一个东西,想要存储哈希数组,并试图发明自己的。无论哪种方式,它都不是一条好的道路。
这是你的定义,在被检索后仍然是一个字符串。它似乎是哈希数组的元素,没有周围的数组[
和]
:
foo = "{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"
它仍然是一个字符串:
foo.class # => String
可以将它重新组合成一个可以评估并转回哈希数组的形式,但它并不简单,也不干净,不方便或优雅。
我怀疑你的原始对象是这样的:
foo = {"monday"=>{:start_time=>9.0, :end_time=>10.5}},{"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},{"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}
# => [{"monday"=>{:start_time=>9.0, :end_time=>10.5}},
# {"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},
# {"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}]
这是一个数组:
foo.class # => Array
现在它是一个数组,因为你有多个用逗号分隔的Hash元素(,
),Ruby在分配给单个变量时会将其解释为数组。这将是一个视觉上不那么令人困惑的例子:
foo = {a: 1}, {a: 2} # => [{:a=>1}, {:a=>2}]
foo.class # => Array
foo.first.class # => Hash
回到foo
中的哈希数组:从那开始,JSON类很容易将其序列化为可以存储在数据库中的字符串,然后检索并重新分解为Ruby对象:
require 'json'
foo.to_json
foo.to_json
会产生一个类似于以下内容的序列化字符串:
[{"monday":{"start_time":9.0,"end_time":10.5}},{"tuesday":{"start_time":8.5,"end_time":10.0}},{"wednesday":{"start_time":8.5,"end_time":10.0}}]
并且,给定该字符串,JSON可以重建对象:
bar = JSON.parse(foo.to_json)
# => [{"monday"=>{"start_time"=>9.0, "end_time"=>10.5}},
# {"tuesday"=>{"start_time"=>8.5, "end_time"=>10.0}},
# {"wednesday"=>{"start_time"=>8.5, "end_time"=>10.0}}]
请注意,不必使用parse
或to_json
。该类足够聪明,可以识别参数是String,Array还是Hash,并分别解析或序列化:
JSON[JSON[foo]]
# => [{"monday"=>{"start_time"=>9.0, "end_time"=>10.5}},
# {"tuesday"=>{"start_time"=>8.5, "end_time"=>10.0}},
# {"wednesday"=>{"start_time"=>8.5, "end_time"=>10.0}}]
此时,您已准备好将值存储到数据库中的String类型字段中,然后稍后检索它们并重复使用它们。
如果您希望搜索或操作那些存储的JSON字符串,我建议您重新思考。虽然现代DBM可以在JSON内部进行搜索并生成它,但最好还是有一个单独的键和值表。它更快,更灵活。
最后针对您的问题,如何转换字符串以便获取键和值:
foo = "{\"monday\"=>\"{:start_time=>9.0, :end_time=>10.5}\"},{\"tuesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"},{\"wednesday\"=>\"{:start_time=>8.5, :end_time=>10.0}\"}"
bar = eval('[' + foo.gsub(/"([{}])/, '\1') + ']')
bar
# => [{"monday"=>{:start_time=>9.0, :end_time=>10.5}},
# {"tuesday"=>{:start_time=>8.5, :end_time=>10.0}},
# {"wednesday"=>{:start_time=>8.5, :end_time=>10.0}}]
bar.map { |h| [h.keys, h.values.first.keys] }
# => [[["monday"], [:start_time, :end_time]],
# [["tuesday"], [:start_time, :end_time]],
# [["wednesday"], [:start_time, :end_time]]]
这暗示哈希数组也不是正确的结构。一个简单的哈希就足够了:
foo = {
"monday"=>{:start_time=>9.0, :end_time=>10.5},
"tuesday"=>{:start_time=>8.5, :end_time=>10.0},
"wednesday"=>{:start_time=>8.5, :end_time=>10.0}
}
require 'json'
bar = JSON[JSON[foo]] # imitate a round-trip to/from the DB
bar.keys # => ["monday", "tuesday", "wednesday"]
bar.values # => [{"start_time"=>9.0, "end_time"=>10.5}, {"start_time"=>8.5, "end_time"=>10.0}, {"start_time"=>8.5, "end_time"=>10.0}]