首页 > 解决方案 > 基于两个哈希的 Ruby Regex 过滤器

问题描述

我正在尝试为 logsatash 构建一个过滤器。它需要在 Ruby 中。
过滤器采用 json 格式的元数据,并基于允许字段的另一个 json,它从元数据中删除所有不匹配的字段。
过滤器的主线是进行评估。如果传递的元数据名称在允许散列的键中,它应该评估为true. (允许散列的所有值都true与示例中的一样,无关紧要)。
在允许的哈希中,可以有一个通配符表示的glob ,在这种情况下它可以匹配任何字符串。 例如表示或可以通过。 但是,如果只有这样的确切字符串可以通过,但没有类似 *
"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等,但没有预期的结果。有使用单个正则表达式的示例,查看字符串数组,但不是其他方式。
构建这样一个过滤器的 Ruby 方法是什么?

标签: rubyregex

解决方案


我假设@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} 

推荐阅读