55

我想命名从扫描中获得的字符串捕获。怎么做?

"555-333-7777".scan(/(\d{3})-(\d{3})-(\d{4})/).flatten #=> ["555", "333", "7777"]

有没有可能变成这样

{:area => "555", :city => "333", :local => "7777" }

或者

[["555","area"], [...]]

我试过了

"555-333-7777".scan(/((?<area>)\d{3})-(\d{3})-(\d{4})/).flatten

但它返回

[]
4

6 回答 6

98

You should use match with named captures, not scan

m = "555-333-7777".match(/(?<area>\d{3})-(?<city>\d{3})-(?<number>\d{4})/)
m # => #<MatchData "555-333-7777" area:"555" city:"333" number:"7777">
m[:area] # => "555"
m[:city] # => "333"

If you want an actual hash, you can use something like this:

m.names.zip(m.captures).to_h # => {"area"=>"555", "city"=>"333", "number"=>"7777"}

Or this (ruby 2.4 or later)

m.named_captures # => {"area"=>"555", "city"=>"333", "number"=>"7777"}
于 2013-09-16T10:27:55.430 回答
6

像这样的东西?

"555-333-7777" =~ /^(?<area>\d+)\-(?<city>\d+)\-(?<local>\d+)$/
Hash[$~.names.collect{|x| [x.to_sym, $~[x]]}]
 => {:area=>"555", :city=>"333", :local=>"7777"}

奖励版本:

Hash[[:area, :city, :local].zip("555-333-7777".split("-"))]
=> {:area=>"555", :city=>"333", :local=>"7777"}
于 2013-09-16T10:40:59.733 回答
1

如果您真的不需要哈希,而只需要局部变量:

if /(?<area>\d{3})-(?<city>\d{3})-(?<number>\d{4})/ =~ "555-333-7777"
  puts area
  puts city
  puts number
end

它是如何工作的?

  • 您需要使用=~正则表达式运算符。
  • 正则表达式(可悲)需要在左边。如果您使用string =~ regex.
  • 否则,它的语法?<var>与 with相同named_captures
  • Ruby 1.9.3 支持它!

官方文档:

当命名捕获组与表达式左侧的文字正则表达式和 =~ 运算符一起使用时,捕获的文本也会分配给具有相应名称的局部变量。

于 2021-05-17T08:48:42.947 回答
0

有很多方法可以创建命名捕获,其中许多已经被提及。不过,为了记录,我们甚至可以Multiple Assignment像这样使用最初发布的代码:

a, b, c =  "555-333-7777".scan(/(\d{3})-(\d{3})-(\d{4})/).flatten
hash = {area: a, city: b, local: c}
#=>  {:area=>"555", :city=>"333", :local=>"7777"}

或者

hash = {}
hash[:area], hash[:city], hash[:local] =  "555-333-7777".scan(/(\d{3})-(\d{3})-(\d{4})/).flatten
hash
#=>  {:area=>"555", :city=>"333", :local=>"7777"}

或连同zip和可选to_h

[:area, :city, :local].zip "555-333-7777".scan(/(\d{3})-(\d{3})-(\d{4})/).flatten
#=>  [[:area, "555"], [:city, "333"], [:local, "7777"]]

([:area, :city, :local].zip "555-333-7777".scan(/(\d{3})-(\d{3})-(\d{4})/).flatten).to_h
#=>  {:area=>"555", :city=>"333", :local=>"7777"}
于 2022-01-26T22:15:01.440 回答
0

将捕获组名称及其值转换为哈希的一种方法是使用带有命名捕获的正则表达式,(?<capture_name>然后访问%~全局“最后匹配”变量。

regex_with_named_capture_groups = %r'(?<area>\d{3})-(?<city>\d{3})-(?<local>\d{4})'
"555-333-7777"[regex_with_named_capture_groups]

match_hash = $~.names.inject({}){|mem, capture| mem[capture] = $~[capture]; mem}
# => {"area"=>"555", "city"=>"333", "local"=>"7777"}

# If ActiveSupport is available
match_hash.symbolize_keys!
# => {area: "555", city: "333", local: "7777"}
于 2017-02-01T08:57:41.957 回答
0

这种替代方法也有效:

regex = /^(?<area>\d+)\-(?<city>\d+)\-(?<local>\d+)$/
m = "555-333-7777".match regex
m.named_captures
 => {"area"=>"555", "city"=>"333", "local"=>"7777"}
于 2022-01-26T16:17:05.660 回答