代码之家  ›  专栏  ›  技术社区  ›  tomasz74

基于两个哈希的Ruby Regex过滤器

  •  0
  • tomasz74  · 技术社区  · 6 年前

    我正试图为罗格萨塔什建立一个过滤器。它应该是红宝石色的。
    过滤器采用JSON格式的元数据,并基于另一个允许字段的JSON,它从元数据中删除所有不匹配的字段。
    过滤器的主线是进行评估。如果传递的元数据名称位于允许哈希的键中,则其计算结果应为 true . (允许哈希的所有值为 就像例子中那样,没关系)。
    在允许的哈希中可以有一个 格洛布 由A代表 通配符 * 在这种情况下,它可以匹配任何字符串。
    例如 "instrument.network.*" 意味着 "instrument.network.one" "instrument.network.abc" 可以通过。
    但是如果没有 * 像在 "event.type" 只有这样的字符串才能通过,但是 "event.type.abc" . 也就是说, * 表示任意数量的字符,类似于正则表达式中的字符。
    简化代码如下:

    # input data
    metadata = {"event.type"=>"message", "instrument.network.one"=>false, "instrument.network.two"=>false, "other.meta"=>true}
    @allowed = {"timestamp"=>true, "event.type"=>true, "network.labels.*"=>true}
    
    metadata.each do |key, val|
      # evaluation to be worked out
      evaluation = (@allowed.has_key? key)
      puts "the #{key} is allowed?: #{evaluation}"
      # metadata clearence
      metadata.delete(key) if !evaluation
    end
    puts "metadata after clearence: #{metadata}"
    

    目前,此代码的输出为:

    the event.type is allowed?: true
    the instrument.network.one is allowed?: false
    the instrument.network.two is allowed?: false
    the other.meta is allowed?: false
    metadata after clearence: {"event.type"=>"message"}
    

    但是我需要让通配符从 "network.labels.*" 输出如下:

    the event.type is allowed?: true
    the instrument.network.one is allowed?: true
    the instrument.network.two is allowed?: true
    the other.meta is allowed?: false
    metadata after clearence: {"event.type"=>"message", "instrument.network.one"=>false, "instrument.network.two"=>false}
    

    我想用 Regexp.union(@allowed) =~ key 但不能这样做。我在尝试其他的红宝石技巧,比如 .find 等等,但没有预期的结果。有一些例子可以使用单个regex,在字符串数组中查找,但不是另一种方法。
    Ruby构建这样一个过滤器的方法是什么?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Cary Swoveland    6 年前

    我假设 @allowed 应该如下。如果最后一个键不是以“instrument.”或“.labels”开头,则通配符“*”的用途不明确。

    @allowed = { "timestamp"=>true, "event.type"=>true,
                 "instrument.network.*"=>true }
    
    arr = @allowed.map { |k,_|
      Regexp.new(k.gsub('.', '\.').sub('*', '.*')) }
      #=> [/timestamp/, /event\.type/, /instrument\.network\..*/] 
    r = /\A#{Regexp.union(arr)}\z/
      #=> /\A(?-mix:(?-mix:timestamp)|(?-mix:event\.type)|(?-mix:instrument\.network\..*))\z/ 
    metadata.select do |k,_|
      res = k.match?(r)
      puts "#{k} is allowed?: #{res}"
      res
    end
    event.type is allowed?: true
    instrument.network.one is allowed?: true
    instrument.network.two is allowed?: true
    other.meta is allowed?: false
      #=> {"event.type"=>"message", "instrument.network.one"=>false, ] 
      #    "instrument.network.two"=>false}