[ruby] String 객체를 Hash 객체로 어떻게 변환합니까?

해시처럼 보이는 문자열이 있습니다.

"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"

해시를 어떻게 제거합니까? 처럼:

{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }

문자열은 중첩 깊이를 가질 수 있습니다. Ruby에서 유효한 해시를 입력하는 방법에 대한 모든 속성이 있습니다.



답변

호출하여 생성 된 문자열은 호출 Hash#inspect하여 해시로 다시 전환 될 수 있습니다.eval . 그러나 이것은 해시의 모든 객체에 대해 동일해야합니다.

hash로 시작하면 {:a => Object.new}문자열 표현은 "{:a=>#<Object:0x7f66b65cf4d0>}"이며 유효한 Ruby 구문이 아니기 eval때문에 문자열을 해시로 되돌릴 수 없습니다 #<Object:0x7f66b65cf4d0>.

그러나 해시에있는 모든 것이 문자열, 기호, 숫자 및 배열이면 유효한 Ruby 구문 인 문자열 표현이 있으므로 작동해야합니다.


답변

다른 문자열의 경우 위험한 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('=>', ':')


답변

빠르고 더러운 방법은

eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 

그러나 보안에 심각한 영향을 미칩니다.
전달 된 모든 것을 실행하면 110 % 확신해야합니다 (적어도 어느 곳에도 사용자 입력이 없어야 함) 제대로 구성된 해시 만 포함하거나 외부 공간에서 예기치 않은 버그 / 끔찍한 생물이 팝업되기 시작할 수 있습니다.


답변

아마 YAML.load?


답변

이 짧은 스 니펫은 그렇게하지만 중첩 된 해시와 함께 작동하는 것을 볼 수 없습니다. 그래도 꽤 귀엽다고 생각합니다

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

단계 1. ‘{‘, ‘}’및 ‘:’를 제거합니다. 2. ‘,’를 찾을 때마다 문자열을 분할합니다. 3. 분할로 생성 된 각 하위 문자열을 찾을 때마다 분할합니다. ‘=>’. 그런 다음 방금 나눈 해시의 양면으로 해시를 만듭니다. 4. 해시 배열이 남은 다음 병합합니다.

입력 예 : “{: user_id => 11, : blog_id => 2, : comment_id => 1}”결과 출력 : { “user_id”=> “11”, “blog_id”=> “2”, “comment_id”= > “1”}


답변

지금까지 솔루션은 일부 사례를 다루었지만 일부 사례는 누락되었습니다 (아래 참조). 보다 철저한 (안전한) 변환을위한 나의 시도는 다음과 같습니다. 이 솔루션이 홀수이지만 허용되는 문자로 구성된 단일 문자 기호를 처리하지 못하는 경우를 알고 있습니다. 예를 들어{:> => :<} 유효한 루비 해시입니다.

코드를 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)

여기 다른 솔루션에 대한 참고 사항이 있습니다.


답변

나는 같은 문제가 있었다. Redis에 해시를 저장하고있었습니다. 해시를 검색 할 때 문자열이었습니다. eval(str)보안 문제 때문에 전화를 걸고 싶지 않았습니다 . 내 솔루션은 해시를 루비 해시 문자열 대신 json 문자열로 저장하는 것이 었습니다. 옵션이 있으면 json을 사용하는 것이 더 쉽습니다.

  redis.set(key, ruby_hash.to_json)
  JSON.parse(redis.get(key))

TL; DR : 사용 to_jsonJSON.parse