【问题标题】:How do I lookup a key/symbol based on which Regex match?如何根据哪个 Regex 匹配查找键/符号?
【发布时间】:2015-08-11 13:46:37
【问题描述】:

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

示例: 我有以下哈希:

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

所以,我有 zip 中每个文件的文件名,假设一个例子是

filename = 382582941917841df.xml

假设每个文件只会匹配labels哈希中的一个Regex,如果不匹配也没关系,只选择第一个匹配。 (在这种情况下,正则表达式都是用于检测扩展名,但也可以是检测任何文件名掩码,例如 DSC****.jpg。

我现在正在这样做:

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

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

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

所以这很好用,但看起来不像 Ruby。有什么我想好好清理的吗?

【问题讨论】:

    标签: ruby regex hash


    【解决方案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 等方法更快且维护更少时,您是否真的希望使用未锚定的正则表达式模式减慢代码速度?

    这些是编写代码时要考虑的事情。

    【讨论】:

    • 感谢您的回答,我将如何更正确地编写该正则表达式。关于文件扩展名,我写了这个“在这种情况下,正则表达式都是用于检测扩展名,但它可能是检测任何文件名掩码,例如 DSC****.jpg”
    • 所以只使用扩展不适合用例
    • 那么您用来确定文件类型的完整规范是什么?照原样,无法解释名称的哪些部分很重要。例如,为什么你捕获'.'之前的字符?通常,文件名的扩展名是文件类型的决定因素。 (即使扩展名不应该这样使用,因为它们甚至可能不存在。)****.jpg 文件中是否重要,或者它是否足以成为“DSC”JPEG 文件?
    • 注册。 exp 是从另一个应用程序一起传入的。所以 full 规范是有许多 label -> regex 对,reg 表达式可以是任何东西,只要它们不重叠。
    【解决方案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
    

    【讨论】:

    • 这是一个很好的答案,不幸的是我可能需要以编程方式添加到这些内容中以排除案例陈述。
    【解决方案3】:

    当不匹配时,不要使用nil 来指示标签,而是考虑使用另一个符号,例如:unknown

    那么你可以这样做:

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

    【讨论】:

    • 我的印象是 Ruby 中的哈希不能保证有顺序,所以这肯定会导致已知文件被归类为未知文件吗?
    • 另外,我仍然需要拒绝未知文件
    • @JohnLinux Hashes 自 1.9 版起维护插入顺序。
    • 如前所述,哈希确实保持插入顺序,因此可以正常工作。当然,您对:unknown 文件的处理取决于您自己。假设您的拒绝过程正在检查 nil,只需检查 unknown
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-17
    相关资源
    最近更新 更多