【问题标题】:Using gsub and regex to replace every other occurrence of a character使用 gsub 和 regex 替换每个其他出现的字符
【发布时间】:2019-02-13 01:51:13
【问题描述】:

我正在设计一款纸牌游戏(黑桃)。我想将每只手存储为哈希。

这是一个随机生成的字符串,表示具有 13 张卡片的单个拥有,其中 10c 是键,10 是值

"10c 10 bj 18 2s 15 3s 3 8d 8 as 14 kh 13 8c 8 3c 3 6d 6 kc 13 5d 5 ad 14"

我想将10c10 之间的空格' ' 替换为=>,并将10bj 之间的以下空格替换为逗号...这应该看起来像10c=>10,bj=>18等等。

从那里我将通过调用 Hash#inspect; 将其转换为哈希;但是,我还没有找到使用 gsub 替换字符串的第 n 个字符的方法。

我试过调用hand.gsub(' ', '=>'),但这显然会用=>替换空间的每个实例

【问题讨论】:

  • str.split.each_slice(2).to_h
  • 这个也可以。
  • 您的目标是创建一个哈希。一种方法是一步使用正则表达式(尽管我不知道gsub 如何适合它)。然而,这不是唯一的方法,而且在我看来,这也不是最好的方法。通过按你的方式提出问题,你不必要地限制了可以使用的方法。这有时被称为XY problem
  • @sawa 如何使用 gsub 替换字符串的第 n 个字符?
  • @kel.o 这个原始请求的答案是s.gsub(/([^ ]* [^ ]*) /, '\1,').gsub(' ', '=>')

标签: regex ruby gsub


【解决方案1】:

您可以立即构建散列

s = "10c 10 bj 18 2s 15 3s 3 8d 8 as 14 kh 13 8c 8 3c 3 6d 6 kc 13 5d 5 ad 14"
hash = Hash[s.scan(/(\w+) (\d+)/)].transform_values(&:to_i)

或者,对于较旧的 Ruby 版本:

hash = Hash[s.scan(/(\w+) (\d+)/)]
hash = Hash[ hash.map{ |a, b| [ a, b.to_i ] } ]
puts hash
# => {"10c"=>10, "bj"=>18, "2s"=>15, "3s"=>3, "8d"=>8, "as"=>14, "kh"=>13, "8c"=>8, "3c"=>3, "6d"=>6, "kc"=>13, "5d"=>5, "ad"=>14}

Ruby demo

(\w+) (\d+) 模式匹配并捕获任何一个或多个单词字符(带有(\w+)、字母、数字或下划线,您可以使用[[:alnum:]]+[^\W_],而不是匹配字母或数字),然后匹配一个空格,然后将任何一个或多个数字 ((\d+)) 捕获到第 2 组。 String#scan 匹配所有不重叠的事件,并且只返回捕获的子字符串,这些子字符串被利用到动态构建的哈希中。

请注意,当您运行 b.to_i 时,您不需要额外的检查,因为 \d+ 只会匹配数字子字符串(并且它们在输入中的长度为 2)。

【讨论】:

  • 如果必须将值转换为int,请使用hash[key] = val.to_i
  • 啊这很有意义。这正是我所需要的。
  • 一个细节:你写它的方式使它看起来scan 正在返回哈希值。考虑在末尾添加hash 行或将前两行替换为s.scan(/(\w+) (\d+)/).each_with_object({}) do |(key, val),hash|
  • 避免每个循环。使用另一种哈希语法Hash[s.scan(/(\w+) (\d+)/)]
  • @Dyaniyal,如果要使用Hash::[],写Hash[*s.split]不是更简单吗,就像我所做的那样?
【解决方案2】:

我不认为使用正则表达式是创建散列的最佳方式。相反,我建议使用String#splitHash::[]Hash#transform_valuesString#to_i 方法。如果s是示例中给出的字符串,

Hash[*s.split].transform_values(&:to_i)
  #=> {"10c"=>10, "bj"=>18, "2s"=>15, "3s"=>3, "8d"=>8,
  #    "as" =>14, "kh"=>13, "8c"=> 8, "3c"=>3, "6d"=>6,
  #    "kc" =>13, "5d"=> 5, "ad"=>14} 

步骤如下。

a = s.split
  #=> ["10c", "10", "bj", ... , "14"] 
b = Hash[*a]
  #=> {"10c"=>"10", "bj"=>"18", "2s"=>"15", "3s"=>"3",
  #    "8d" => "8", "as"=>"14", "kh"=>"13", "8c"=>"8",
  #    "3c" => "3", "6d"=> "6", "kc"=>"13", "5d"=>"5",
  #    "ad" =>"14"} 
b.transform_values(&:to_i)
  #=> {"10c"=>10, "bj"=>18, "2s"=>15, "3s"=>3, "8d"=>8,
  #    "as" =>14, "kh"=>13, "8c"=> 8, "3c"=>3, "6d"=>6,
  #    "kc" =>13, "5d"=> 5, "ad"=>14} 

splat 运算符 (*) 导致 Hash[*a] 被评估为 Hash["10c", "10", "bj", ... , "14"]

b.transform_values(&:to_i) 在这里等同于b.transform_values { |v| v.to_i }

【讨论】:

  • transform_values(&:to_i) 行的目的是什么?看来拆分字符串并在新数组上调用 splat 运算符就足够了。
  • @kel.o,问题要求值是整数,而不是字符串。我对我的答案做了一个小改动,用返回的哈希替换了可能模棱两可的行 #=> (the hash given above)
猜你喜欢
  • 1970-01-01
  • 2011-09-13
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多