Ruby中的通配符字符串匹配
我想编写一个实用函数/模块,它将提供与字符串的简单通配符/全局匹配。我不使用正则表达式的原因是,最终用户将使用某种配置文件提供匹配的模式。我找不到任何这样的宝石是稳定的-尝试过的小丑,但它有问题设置 我想要的功能很简单。例如,给定以下模式,以下是匹配项:Ruby中的通配符字符串匹配,ruby,pattern-matching,glob,string-matching,Ruby,Pattern Matching,Glob,String Matching,我想编写一个实用函数/模块,它将提供与字符串的简单通配符/全局匹配。我不使用正则表达式的原因是,最终用户将使用某种配置文件提供匹配的模式。我找不到任何这样的宝石是稳定的-尝试过的小丑,但它有问题设置 我想要的功能很简单。例如,给定以下模式,以下是匹配项: pattern | test-string | match ========|=====================|==================== *hn | john, johnny, hanna |
pattern | test-string | match
========|=====================|====================
*hn | john, johnny, hanna | true , false, false # wildcard , similar to /hn$/i
*hn* | john, johnny, hanna | true , true , false # like /hn/i
hn | john, johnny, hanna | false, false, false # /^hn$/i
*h*n* | john, johnny, hanna | true , true , true
etc...
我希望这是尽可能有效的。我曾考虑过从模式字符串创建正则表达式,但在运行时这样做似乎效率很低。对这一实施有何建议?谢谢
编辑:我正在使用ruby 1.8.7
def create_regex(pattern)
if pattern[0,1] != '*'
pattern = '[^\w\^]' + pattern
end
if pattern[-1,1] != '*'
pattern = pattern + '[^\w$]'
end
return Regexp.new( pattern.gsub(/\*/, '.*?') )
end
此MethodId应返回您的regexp
附言:它没有经过测试:我不明白你为什么认为它效率低下。关于这类事情的预测是出了名的不可靠,你应该决定它太慢了,然后再回头去寻找更快的方法。然后你应该分析它,以确保这是问题所在(顺便说一句,从切换到1.9,平均速度提高了3-4倍) 无论如何,这应该很容易做到,比如:
class Globber
def self.parse_to_regex(str)
escaped = Regexp.escape(str).gsub('\*','.*?')
Regexp.new "^#{escaped}$", Regexp::IGNORECASE
end
def initialize(str)
@regex = self.class.parse_to_regex str
end
def =~(str)
!!(str =~ @regex)
end
end
glob_strs = {
'*hn' => [['john', true, ], ['johnny', false,], ['hanna', false]],
'*hn*' => [['john', true, ], ['johnny', true, ], ['hanna', false]],
'hn' => [['john', false,], ['johnny', false,], ['hanna', false]],
'*h*n*' => [['john', true, ], ['johnny', true, ], ['hanna', true ]],
}
puts glob_strs.all? { |to_glob, examples|
examples.all? do |to_match, expectation|
result = Globber.new(to_glob) =~ to_match
result == expectation
end
}
# >> true
我认为以
'*hn'
为例,他需要'john's awesome'
也返回true,而/.*hn$/
将不会匹配globs在我的计算机上的工作方式(Mac OSX Leopard)我认为通配符比glob更准确——对于'*hn'
上的情况,我希望模式之前和之后的所有内容都要匹配,后面什么都不匹配;所以true
对于'john'
,false
对于'john is..
。感谢与此解决方案一致的内容。完成了一些编辑-感谢指出语法错误-perl/php:D太多了