[英]Ruby: split string in hash
我有一个字符串
str = "race_1: 650m, 215m, 265m, 315m\r\nrace_2: 165m, 215m, 265m, 315m."
预期结果:我想像这样将其拆分为 hash:
hash = {
race_1 => [650, 215, 265, 315],
race_2 => [165, 215, 265, 315]
}
有人可以指导我创建匹配 hash 的方向吗?
当输入始终遵循相同的模式时,我会使用String#scan
和 Regexp 来提取重要值。
string = "race_1: 650m, 215m, 265m, 315m\r\nrace_2: 165m, 215m, 265m, 315m."
regexp = /(race_\d+).*?(\d+(?=m)).*?(\d+(?=m)).*?(\d+(?=m)).*?(\d+(?=m))/
string.scan(regexp)
#=> [["race_1", "650", "215", "265", "315"], ["race_2", "165", "215", "265", "315"]]
然后可以将这些嵌套的值数组转换为 hash,如下所示:
string.scan(regexp).to_h { |values| [values[0], values[1..-1]] }
#=> {"race_1"=>["650", "215", "265", "315"], "race_2"=>["165", "215", "265", "315"]}
并且因为您希望数组中的数字是整数:
string.scan(regexp).to_h { |values| [values[0], values[1..-1].map(&:to_i)] }
#=> {"race_1"=>[650, 215, 265, 315], "race_2"=>[165, 215, 265, 315]}
以下允许任意数量的比赛,并且每场比赛都有任意数量的相关距离(在下面的str
中有四个)。
str = "race_1: 650m, 215m, 265m, 315m\r\nrace_2: 165m, 215m, 265m, 315m"
str.gsub(/(\w+): ((?:\d+m, *)*\d+)/).with_object({}) do |_s,h|
h[$1] = $2.split(',').map(&:to_i)
end
#=> {"race_1"=>[650, 215, 265, 315],
# "race_2"=>[165, 215, 265, 315]}
这采用了一种很少使用(并且被大大低估了)的String#gsub形式,它采用单个参数但没有块,并返回一个枚举器。 枚举器仅生成gsub
参数的匹配项,因此与字符串替换无关。 当scan
的参数是包含一个或多个捕获组的正则表达式时,这种形式的gsub
有时是String#scan的方便替代品。
作为gsub
参数的正则表达式可以用自由间距模式表示,以使其自记录。
/
( # begin capture group 1
\w+ # match >= 1 word characters
) # end capture group 1
: # match a colon
[ ] # match a space
( # begin capture group 2
(?: # begin non-capture group
\d+ # match >= 1 digits
m,[ ]* # match "m," followed by >= 0 spaces
) # end non-capture group
* # execute preceding non-capture group >= 0 times
\d+ # match >= 1 digits
) # end capture group 2
/x # invoke free-spacing regex definition mode
请注意,在自由间距模式中,作为表达式一部分的空格必须受到保护。 有多种方法可以做到这一点。 我已将每个空格括在一个字符 class ( [ ]
) 中。
在上面的示例中,我们计算了以下枚举器。
enum = str.gsub(/(\w+): ((?:\d+m, *)*\d+)/)
#=> #<Enumerator: "race_1: 650m, 215m, 265m, 315m\r\n
# race_2: 165m, 215m, 265m, 315m":
# gsub(/(\w+): ((?:\d+m, *)*\d+)/)>
它将生成的元素如下。
enum.next
#=> "race_1: 650m, 215m, 265m, 315"
enum.next
#=> "race_2: 165m, 215m, 265m, 315"
enum.next
#=> StopIteration: iteration reached an end
还要注意的是
arr = "650m, 215m, 265m, 315".split(',')
#=> ["650m", " 215m", " 265m", " 315"]
arr.map(&:to_i)
#=> [650, 215, 265, 315]
这个的一个变体是写
rgx = /\w+: (?:\d+m, *)*\d+/
str.gsub(rgx).with_object({}) do |s,h|
key, value = s.split(':')
h[key] = value.split(',').map(&:to_i)
end
#=> {"race_1"=>[650, 215, 265, 315],
# "race_2"=>[165, 215, 265, 315]}
由于正则表达式现在没有捕获组,所以当第一行替换为
str.scan(rgx).each_with_object({}) do |s,h|
你可以写这段代码
输入
str = "race_1: 650m, 215m, 265m, 315m\r\nrace_2: 165m, 215m, 265m, 315m."
代码
用冒号拆分代码:并替换末尾的 m
hash = str.scan(/(race_\d+): (.*)/).each_with_object({}) do |(race, distances), hash|
hash["#{race}"] = distances.split(', ').map { |d| d.sub(/m$/, '').to_i }
end
p hash
Output
{"race_1"=>[650, 215, 265, 315], "race_2"=>[165, 215, 265, 315]}
你能试试下面的代码吗?
str = "race_1: 650m, 215m, 265m, 315m\r\nrace_2: 165m, 215m, 265m, 315m."
rows = str.delete('.').split("\r\n") # => ["race_1: 650m, 215m, 265m, 315m", "race_2: 165m, 215m, 265m, 315m"]
hash_result = {}
rows.each do |row|
key = row.split(':').first # => race_1
value = row.split(':').last.split('m, ').map(&:to_i) # => [650, 215, 265, 315]
hash_result[key.to_sym] = value
end
# hash_result = {:race_1=>[650, 215, 265, 315], :race_2=>[165, 215, 265, 315]}
p/s: 我觉得你应该自己动手来提升自己
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.