如何将String对象转换为Hash对象?

Was*_*eem 128 ruby

我有一个看起来像哈希的字符串:

"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"
Run Code Online (Sandbox Code Playgroud)

如何从中获取哈希值?喜欢:

{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }
Run Code Online (Sandbox Code Playgroud)

字符串可以具有任何嵌套深度.它具有在Ruby中键入有效Hash的所有属性.

zol*_*ter 140

对于不同的字符串,您可以不使用危险eval方法来执行此操作:

hash_as_string = "{\"0\"=>{\"answer\"=>\"1\", \"value\"=>\"No\"}, \"1\"=>{\"answer\"=>\"2\", \"value\"=>\"Yes\"}, \"2\"=>{\"answer\"=>\"3\", \"value\"=>\"No\"}, \"3\"=>{\"answer\"=>\"4\", \"value\"=>\"1\"}, \"4\"=>{\"value\"=>\"2\"}, \"5\"=>{\"value\"=>\"3\"}, \"6\"=>{\"value\"=>\"4\"}}"
JSON.parse hash_as_string.gsub('=>', ':')
Run Code Online (Sandbox Code Playgroud)

  • 你还应该替换 nils, fe `JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))` (5认同)
  • 应该选择此答案以避免使用eval。 (2认同)
  • 不幸的是,不适用于符号... (2认同)

Tom*_*oss 132

快速而肮脏的方法将是

eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 
Run Code Online (Sandbox Code Playgroud)

但它具有严重的安全隐患.
它执行它传递的任何东西,你必须110%肯定(因为,至少没有用户输入的任何地方)它将只包含正确形成的哈希或来自外太空的意外错误/可怕的生物可能会开始弹出.

  • 我有一把轻剑.我可以照顾那些生物和虫子.:) (15认同)
  • 我不能强调在这里使用EVAL的危险!如果用户输入可以进入你的字符串,这是绝对禁止的. (13认同)
  • 据我的老师说,使用EVAL在这里可能很危险.Eval接受任何ruby代码并运行它.这里的危险类似于SQL注入危险.Gsub是优选的. (11认同)
  • 示例字符串显示为什么David的老师是正确的:'{:surprise =>"#{system \"rm -rf*\"}"}' (9认同)

Ken*_*oom 77

通过调用创建的字符串Hash#inspect可以通过调用eval它返回到哈希.但是,这要求哈希中的所有对象都是如此.

如果我从哈希开始{:a => Object.new},那么它的字符串表示是"{:a=>#<Object:0x7f66b65cf4d0>}",并且我不能用eval它将它变回哈希,因为#<Object:0x7f66b65cf4d0>它不是有效的Ruby语法.

但是,如果散列中的所有内容都是字符串,符号,数字和数组,那么它应该可以工作,因为它们具有有效Ruby语法的字符串表示.

  • 在你使用它的地方是小心翼翼的.在错误的地方使用'eval`是一个巨大的安全漏洞.将对字符串中的任何内容进行评估.所以想象一下如果在API中有人注入`rm -fr` (10认同)

sil*_*ent 23

也许是YAML.load?

  • 这需要完全不同的字符串表示,但它更安全.(并且字符串表示也很容易生成 - 只需调用#to_yaml,而不是#inspect) (4认同)

hrd*_*rbl 23

这个简短的小片段会做到这一点,但我看不到它使用嵌套哈希.我觉得它很可爱

STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)
Run Code Online (Sandbox Code Playgroud)

步骤1.我消除了'{','}'和':'2.我在字符串中找到一个','3分开.我将每个用分割创建的子串分开,只要它找到a'=>'.然后,我创建一个哈希,我刚刚分开的哈希的两边.我留下了一系列哈希,然后我合并在一起.

示例输入:"{:user_id => 11,:blog_id => 2,:comment_id => 1}"结果输出:{"user_id"=>"11","blog_id"=>"2","comment_id"= > "1"}

  • 这会不会从字符串化哈希中的*values*中删除`{}:`字符? (3认同)

gen*_*ood 18

到目前为止,解决方案涵盖了一些案例,但遗漏了一些(见下文).这是我尝试进行更彻底(安全)的转换.我知道这个解决方案没有处理的一个角落案例,它是由奇数但允许的字符组成的单个字符符号.例如,{:> => :<}是一个有效的ruby哈希.

我把这个代码放在github上.此代码以测试字符串开头,以执行所有转换

require 'json'

# Example ruby hash string which exercises all of the permutations of position and type
# See http://json.org/
ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

puts ruby_hash_text

# Transform object string symbols to quoted strings
ruby_hash_text.gsub!(/([{,]\s*):([^>\s]+)\s*=>/, '\1"\2"=>')

# Transform object string numbers to quoted strings
ruby_hash_text.gsub!(/([{,]\s*)([0-9]+\.?[0-9]*)\s*=>/, '\1"\2"=>')

# Transform object value symbols to quotes strings
ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>\s*:([^,}\s]+\s*)/, '\1\2=>"\3"')

# Transform array value symbols to quotes strings
ruby_hash_text.gsub!(/([\[,]\s*):([^,\]\s]+)/, '\1"\2"')

# Transform object string object value delimiter to colon delimiter
ruby_hash_text.gsub!(/([{,]\s*)(".+?"|[0-9]+\.?[0-9]*)\s*=>/, '\1\2:')

puts ruby_hash_text

puts JSON.parse(ruby_hash_text)
Run Code Online (Sandbox Code Playgroud)

以下是其他解决方案的一些注意事项


Jar*_*ard 14

我有同样的问题.我在Redis中存储哈希.检索该哈希时,它是一个字符串.出于eval(str)安全考虑,我不想打电话.我的解决方案是将散列保存为json字符串而不是ruby散列字符串.如果你有选择,使用json更容易.

  redis.set(key, ruby_hash.to_json)
  JSON.parse(redis.get(key))
Run Code Online (Sandbox Code Playgroud)

TL; DR:使用to_jsonJSON.parse

  • 对于那些贬低我的人 为什么?我遇到了同样的问题,试图将ruby哈希的字符串表示转换为实际的哈希对象.我意识到我正试图解决错误的问题.我意识到解决这里提出的问题是容易出错和不安全的.我意识到我需要以不同方式存储我的数据,并使用一种旨在安全地序列化和反序列化对象的格式.TL; DR:我和OP有同样的问题,并意识到答案是问一个不同的问题.此外,如果您向我投票,请提供反馈,以便我们可以一起学习. (3认同)
  • 没有解释性评论的Downvoting是Stack Overflow的癌症. (3认同)
  • 这是迄今为止最好的答案。```to_json``` 和 ```JSON.parse``` (2认同)
  • 为了使这个答案更适用于OP的问题,如果你的字符串表示哈希被称为'strungout'你应该能够做hashit = JSON.parse(strungout.to_json),然后通过hashit在hashit中选择你的项目[ 'keyname']正常. (2认同)

c.a*_*zon 11

我更喜欢滥用ActiveSupport :: JSON.他们的方法是将哈希转换为yaml然后加载它.不幸的是,转换为yaml并不简单,如果你的项目中没有AS,你可能想从AS借用它.

我们还必须将任何符号转换为常规字符串键,因为符号在JSON中不合适.

但是,它无法处理其中包含日期字符串的哈希值(我们的日期字符串最终没有被字符串包围,这是大问题的来源):

string ='{'last_request_at':2011-12-28 23:00:00 UTC}' ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\\1').gsub('=>', ' : '))

尝试解析日期值时,将导致无效的JSON字符串错误.

会喜欢有关如何处理此案例的任何建议

  • 感谢指向.decode的指针,它对我很有用.我需要转换JSON响应来测试它.这是我使用的代码:`ActiveSupport :: JSON.decode(response.body,symbolize_keys:true)` (2认同)

Eug*_*ene 9

适用于rails 4.1并支持不带引号的符号{:a =>'b'}

只需将此添加到初始化文件夹:

class String
  def to_hash_object
    JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\\1"').gsub('=>', ': ')).symbolize_keys
  end
end
Run Code Online (Sandbox Code Playgroud)