해시처럼 보이는 문자열이 있습니다.
"{ :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)
여기 다른 솔루션에 대한 참고 사항이 있습니다.
- @ Ken Bloom 과 @Toms Mikoss 의 솔루션
eval
은 너무 무섭습니다 (Toms가 올바르게 지적했듯이). - @zolter 의 솔루션 사용자의 해시 어떤 기호 나 숫자 키가없는 경우 작동합니다.
- @jackquack 의 솔루션 은 따옴표로 묶인 문자열이 기호와 섞이지 않으면 작동합니다.
- @Eugene 의 솔루션 은 기호가 허용되는 모든 문자를 사용하지 않는 경우 작동합니다 ( 심볼 리터럴에는 더 넓은 허용 문자 집합이 있음 ).
- @Pablo 의 솔루션 은 기호와 따옴표로 묶인 문자열이없는 한 작동합니다.
답변
나는 같은 문제가 있었다. Redis에 해시를 저장하고있었습니다. 해시를 검색 할 때 문자열이었습니다. eval(str)
보안 문제 때문에 전화를 걸고 싶지 않았습니다 . 내 솔루션은 해시를 루비 해시 문자열 대신 json 문자열로 저장하는 것이 었습니다. 옵션이 있으면 json을 사용하는 것이 더 쉽습니다.
redis.set(key, ruby_hash.to_json)
JSON.parse(redis.get(key))
TL; DR : 사용 to_json
및JSON.parse