如何根据正则表达式匹配来查找键/符号?

时间:2015-05-28 20:55:58

标签: ruby regex hash

我使用RubyZip从Ruby中的zip存档中提取文件,我需要根据文件名的特征标记文件:

实施例: 我有以下哈希:

labels = {
   :data_file=>/.\.dat/i, 
   :metadata=>/.\.xml/i,
   :text_location=>/.\.txt/i
 }

所以,我在zip中有每个文件的文件名,让我们说一个例子是

filename = 382582941917841df.xml

假设每个文件只匹配labels哈希中的一个正则表达式,如果不匹配则无关紧要,只需选择第一个匹配项即可。 (在这种情况下,正则表达式都用于检测扩展,但它可以检测任何文件名掩码,例如DSC ****。jpg。

我现在正在这样做:

label_match =~ labels.find {|key,value| filename =~ value}

---> label_match = [:metadata, /.\.xml/]

label_sym = label_match.nil? ? nil: label_match.first 

所以这很好用,但看起来并不像Ruby那样。我有什么遗漏可以很好地清理它吗?

3 个答案:

答案 0 :(得分:2)

case when毫不费力地做到了这一点:

filename = "382582941917841df.xml"

category = case filename 
  when /.\.dat/i ; :data_file
  when /.\.xml/i ; :metadata
  when /.\.txt/i ; :text_location
end

p category # => :metadata ; nil if nothing matched

答案 1 :(得分:1)

我认为你正在倒退而且艰难。 Ruby可以轻松获取文件的扩展名,然后可以轻松地将其映射到某个文件。

从以下内容开始:

FILENAMES = %w[ foo.bar foo.baz 382582941917841df.xml DSC****.jpg]

FILETYPES = {
  '.bar' => 'bar',
  '.baz' => 'baz',
  '.xml' => 'metadata',
  '.dat' => 'data',
  '.jpg' => 'image'
}

FILENAMES.each do |fn|
  puts "#{ fn } is a #{ FILETYPES[File.extname(fn)] } file"
end
# >> foo.bar is a bar file
# >> foo.baz is a baz file
# >> 382582941917841df.xml is a metadata file
# >> DSC****.jpg is a image file

File.extname内置于Ruby中。 File类包含许多类似的方法,可用于查找操作系统已知的文件和/或撕开文件路径和文件名,因此非常熟悉它是非常好的事情。

理解不正确编写的正则表达式(例如/.\.dat/i)可能会导致很多痛苦,这一点也很重要。考虑这些:

'foo.xml.dat'[/.\.dat/] # => "l.dat"
'foo.database.20010101.csv'[/.\.dat/] # => "o.dat"
  • 文件是否真的"数据"文件?
  • 为什么分隔.前面的字符重要或必要?
  • extname等方法更快,维护更少时,您是否真的希望使用无锚的正则表达式模式来降低代码速度?

编写代码时需要考虑的事项。

答案 2 :(得分:0)

不要在没有匹配时使用nil来指示标签,而是考虑使用其他符号,例如:unknown

然后你可以这样做:

labels = {
  :data_file=>/.\.dat/i, 
  :metadata=>/.\.xml/i,
  :text_location=>/.\.txt/i,
  :unknown=>/.*/
}
label = labels.find {|key,value| filename =~ value}.first