将此字符串转换为哈希数组

时间:2014-07-02 00:29:27

标签: ruby-on-rails ruby

在Ruby或Rails中转换此字符串的最简洁方法是什么:

"[{one:1, two:2, three:3, four:4},{five:5, six:6}]"

像这样的哈希数组:

[{one:1, two:2, three:3, four:4},{five:5, six:6}]

5 个答案:

答案 0 :(得分:4)

这是一行两行:

s.split(/}\s*,\s*{/).
  map{|s| Hash[s.scan(/(\w+):(\d+)/).map{|t| proc{|k,v| [k.to_sym, v.to_i]}.call(*t)}]}

NB 我使用split(":")将键与值分开,但@Cary Swoveland在正则表达式中使用parens的效果更低。然而,他忘记了关键和价值转换。

或者稍微短一些,但是使用数组索引而不是proc,有些人可能会觉得没有吸引力:

s.split(/}\s*,\s*{/).
  map{|s| Hash[s.scan(/(\w+):(\d+)/).map{|t| [t[0].to_sym, t[1].to_i]}]}

<强>结果:

=> [{:one=>1, :two=>2, :three=>3, :four=>4}, {:five=>5, :six=>6}]

说明:从头开始。最后一个映射处理"key: value"形式的字符串列表,并返回[:key, value]对的列表。 scan将一串逗号分隔的键值对处理成"key: value"个字符串列表。最后,初始拆分分隔括号括起来的逗号分隔字符串。

答案 1 :(得分:1)

试试这个:

"[{one:1, two:2, three:3, four:4},{five:5, six:6}]".
  split(/\}[ ]*,[ ]*\{/).
  map do |h_str| 
    Hash[
      h_str.split(",").map do |kv| 
        kv.strip.
          gsub(/[\[\]\{\}]/, '').
          split(":")
      end.map do |k, v|
        [k.to_sym, v.to_i]
      end
    ]
  end

答案 2 :(得分:0)

不漂亮,没有优化,但解决了它。 (虽然这很有趣:))

a = "[{one:1, two:2, three:3, four:4},{five:5, six:6}]"
array = []
a.gsub(/\[|\]/, '').split(/{|}/).map{ |h| h if h.length > 0 && h != ','}.compact.each do |v|
  hsh = {}
  v.split(',').each do |kv|
    arr = kv.split(':')
    hsh.merge!({arr.first.split.join.to_sym => arr.last.to_i})
  end
  array << hsh
end

如果您想让我解释一下,请问。

答案 3 :(得分:0)

你可以这样做。

编辑:我最初是在匆匆忙忙地准备这个答案,在旅途中,借助一台带有不熟悉的操作系统的计算机(Windows)。在@sawa指出错误之后,我开始着手解决它,但是对于这样做的机制感到非常沮丧,所以我放弃并删除了我的答案。现在我又回到了家,我已经做出了我认为必要的更正。

<强>代码

def extract_hashes(str)
  str.scan(/\[?{(.+?)\}\]?/)
     .map { |arr| Hash[arr.first
                          .scan(/\s*([a-z]+)\s*:\d*(\d+)/)
                          .map { |f,s| [f.to_sym, s.to_i] }
                      ]
          }
end

示例

str = "[{one:1, two:2, three:3, four:4},{five:5, six:6}]"
extract_hashes(str)
  #=> [{:one=>1, :two=>2, :three=>3, :four=>4}, {:five=>5, :six=>6}]

<强>解释

对于上例中的str

a = str.scan(/\[?{(.+?)\}\]?/)
  #=> [["one:1, two:2, three:3, four:4"], ["five:5, six:6"]]

Enumerable#map首先将a的第一个元素传递给块并将其分配给块变量:

arr #=> ["one:1, two:2, three:3, four:4"]

然后

b = arr.first
  #=> "one:1, two:2, three:3, four:4"
c = b.scan(/\s*([a-z]+)\s*:\d*(\d+)/)
  #=> [["one", "1"], ["two", "2"], ["three", "3"], ["four", "4"]]
d = c.map { |f,s| [f.to_sym, s.to_i] }
  #=> [[:one, 1], [:two, 2], [:three, 3], [:four, 4]]
e = Hash[d]
  #=> {:one=>1, :two=>2, :three=>3, :four=>4}

在Ruby 2.0中,Hash[d]可以替换为d.to_h

因此,a的第一个元素被映射到e

接下来,外部mapa的第二个和最后一个元素传递到块中

arr #=> ["five:5, six:6"]

我们获得:

Hash[arr.first
        .scan(/\s*([a-z]+)\s*:\d*(\d+)/)
        .map { |f,s| [f.to_sym, s.to_i] }
    ]
  #=> {:five=>5, :six=>6}

取代a.last

答案 4 :(得分:0)

另一种方法:您的字符串看起来像YAML或JSON -definition:

YAML

略微修改的字符串有效:

require 'yaml'
p YAML.load("[ { one: 1, two: 2, three: 3, four: 4}, { five: 5, six: 6 } ]")
#-> [{"one"=>1, "two"=>2, "three"=>3, "four"=>4}, {"five"=>5, "six"=>6}]

有两个问题:

  1. 键是字符串,没有符号
  2. 您需要更多空格(one:1无法识别,您需要one: 1)。
  3. 问题1你需要一个gsub(/:/, ': ')(我希望你的字符串中没有其他的)

    问题2是already a questionHash[a.map{|(k,v)| [k.to_sym,v]}]

    完整示例:

    require 'yaml'
    input = "[{one:1, two:2, three:3, four:4},{five:5, six:6}]"
    input.gsub!(/:/, ': ')  #force correct YAML-syntax
    p YAML.load(input).map{|a| Hash[a.map{|(k,v)| [k.to_sym,v]}]}
    #-> [{:one=>1, :two=>2, :three=>3, :four=>4}, {:five=>5, :six=>6}]
    

    JSON

    使用json,您需要添加",但符号化更容易:

    require 'json'
    input = '[ { "one":1, "two": 2, "three": 3, "four": 4},{ "five": 5, "six": 6} ]'   
    
    p JSON.parse(input)
    #-> [{"one"=>1, "two"=>2, "three"=>3, "four"=>4}, {"five"=>5, "six"=>6}]
    p JSON.parse(input, :symbolize_names => true)
    #-> [{:one=>1, :two=>2, :three=>3, :four=>4}, {:five=>5, :six=>6}]
    

    原始字符串示例:

    require 'json'
    
    input = "[{one: 1, two: 2, three:3, four:4},{five:5, six:6}]"
    input.gsub!(/([[:alpha:]]+):/, '"\1":')    
    p JSON.parse(input)
    #-> [{"one"=>1, "two"=>2, "three"=>3, "four"=>4}, {"five"=>5, "six"=>6}]
    p JSON.parse(input, :symbolize_names => true)
    #-> [{:one=>1, :two=>2, :three=>3, :four=>4}, {:five=>5, :six=>6}]