我正在开发一个Ruby项目,用户可以在其中配置正则表达式列表,并将每个表达式与要执行的某个操作相关联。然后针对某个给定的输入字符串测试该表达式列表,并且将执行匹配表达式的处理程序。代码基本上如下所示:
@mapping = {
/^[A-Za-z]+$/ => Proc.new { puts "Got word" },
/^\d+$/ => Proc.new { puts "Got number" },
/^.$/ => Proc.new { puts "Got single character" }
}
def run_handlers(s)
@mapping.each { |regexp, handler| handler.call if regexp =~ s.to_s }
end
# Prints 'Got word'
run_handlers("StackOverflow")
# Prints 'Got number' as well as 'Got single character'
run_handlers(4)
唉,当有很多(几千个)处理程序时,这表现得相当糟糕。对所有处理程序执行线性搜索似乎有点浪费,但由于表达式是用户可配置的,因此我无法轻易地利用表达式的某些特定特征。我想知道是否有更有效的方法来做到这一点。
我正在考虑的一个想法是将多个正则表达式(即多个状态机)合并到一个能够更有效地运行的大型状态机中。我知道合并正则表达式的union
方法,但由于我需要根据哪个表达式匹配执行一组不同的处理程序,这似乎没什么用。
我在想,也许表达式可以在内部像树结构一样进行管理(很像Trie,这样程序实际上不需要尝试所有正则表达式,但可以快速删除整个表达式集。
也许已经存在一些针对此类问题的现有代码?我想各种Web框架在获取请求时必须处理相同类型的问题,并且必须决定选择哪条路由。
答案 0 :(得分:1)
您可以使用括号捕获正则表达式匹配的部分。看看这个:
['1','a','Z'].each {|x| p /((\d)|([a-z])|([A-Z]))/.match(x).to_a }
我通过其/((\d)|([a-z])|([A-Z]))/
方法将三个字符串传递给正则表达式match
。然后我将输出转换为数组,以便于比较。
它包含三个正则表达式元素:
(\d) # any number
([a-z]) # lowercase letters
([A-Z]) # uppercase letters
请注意,每个都括在括号内。
然后将它们全部包含在an OR block:(a|b|c)
输出:
["1", "1", "1", nil, nil]
["a", "a", nil, "a", nil]
["Z", "Z", nil, nil, "Z"]
第一个匹配是完整正则表达式的匹配,第二个匹配是外部OR块。
所以这是感兴趣的第三到第五场比赛。它们与内在元素相匹配。
我认为你可能遇到的主要问题是内部元素本身是否具有OR块和捕获块。例如,看看我的代码的这个变种:
['1','a','Z'].each {|x| p /((\d)|(([a-g])|([h-z]))|([A-Z]))/.match(x).to_a }
在此我将第二个元素分成两个(([a-g])|([h-z]))
。
从输出中可以看出,这会抛出结果:
["1", "1", "1", nil, nil, nil, nil]
["a", "a", nil, "a", "a", nil, nil]
["Z", "Z", nil, nil, nil, nil, "Z"]
因此,如果您无法控制每个正则表达式元素的结构,我就不会认为您能够预测输出的结构。