如何在Ruby中进行命名捕获

50pmv0ei  于 12个月前  发布在  Ruby
关注(0)|答案(7)|浏览(100)

我想命名的字符串,我从扫描捕获.怎么做?

"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

但它又回来了

[]
txu3uszq

txu3uszq1#

您应该将match用于命名捕获,而不是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"

如果你想要一个实际的哈希值,你可以使用这样的东西:

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

或者这个(ruby 2.4或更高版本)

m.named_captures # => {"area"=>"555", "city"=>"333", "number"=>"7777"}
km0tfn4u

km0tfn4u2#

像这样吗

"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"}
wdebmtf2

wdebmtf23#

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

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

它是如何工作的?

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

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

eqoofvh9

eqoofvh94#

将捕获组名称及其值转换为散列的一种方法是使用正则表达式和使用(?<capture_name>命名的捕获,然后访问%~全局“last match”变量。

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"}
pnwntuvh

pnwntuvh5#

这种替代方案也适用:

regex = /^(?<area>\d+)\-(?<city>\d+)\-(?<local>\d+)$/
m = "555-333-7777".match regex
m.named_captures
 => {"area"=>"555", "city"=>"333", "local"=>"7777"}
fxnxkyjh

fxnxkyjh6#

有很多方法可以创建命名捕获,其中许多已经提到过。不过,为了记录在案,我们甚至可以像这样使用最初发布的代码沿着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"}

沿着与zipto_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"}
lstz6jyr

lstz6jyr7#

新的symbolize_names: true选项可用于Ruby 3.3+中的MatchData#named_captures
如果关键字参数symbolize_names被赋予true值,则结果散列中的键为Symbols

m = /(?<a>.)(?<a>.)/.match("01")  # => #<MatchData "01" a:"0" a:"1">

m.named_captures #=> {"a" => "1"}
m.named_captures(symbolize_names: true) #=> {:a => "1"}

相关问题