gpt4 book ai didi

ruby - 将字符串近似匹配到列表并在 Ruby 中返回值的最简洁方法?

转载 作者:太空宇宙 更新时间:2023-11-03 16:32:46 26 4
gpt4 key购买 nike

我想在 Ruby 中构建一个函数,它接收一个字符串并将其与可能性列表进行比较,然后返回某个值或函数。这是一个(可能是幼稚的)方法,它可以写成一个 case 语句:

a = 'unicorn'
case a
when "gnome", "dwarf", "hobbit"
"dwarf"
when "dragon"
puts "run away!"
when "centaur", "unicorn"
magical_equine_function(a)
else
false
end

我的问题是,如何使用像 amatch 这样的近似匹配库来做同样的事情? , 这样你就可以设置一个匹配值(比如 2),并且当你有 a = "Unicorn"或 a = "uncorn"时仍然得到匹配?

此外,是否有一种更简洁、更易于维护的方式来编写所有这些内容,方法是通过 YAML 文件播种/比较所有可能的匹配项,而不是写出大量的 case 语句?我是 YAML 的新手,但我希望我可以像这样加载一个文件:

? 
-"gnome"
-"dwarf"
-"hobbit"
:
-"dwarf"
?
-"dragon"
:
-puts "run away"
?
-"centaur"
-"unicorn"
:
-magical_equine_function(a)

然后只对加载的文件进行近似匹配。有没有一种方法可以在不影响性能的情况下做到这一点?

最佳答案

有几种方法可以给这只猫剥皮。一种是使用 lambda:

MATCHERS = [
[/^gnome|dwarf|hobbit$/, lambda { |a| 'dwarf' }],
['dragon', lambda { |a| puts 'run away!' }],
[/^centaur|unicorn$/, lambda { |a| magical_equine_function(a) }],
[//, lambda { |a| false }],
]

这将模式(可以是字符串或正则表达式)与 lambda 相关联。最后一个匹配器很特别:它是一个可以匹配任何东西的哨兵。它代表您示例中的 else 子句。

这是进行匹配的代码:

def match(a)
MATCHERS.each do |pattern, f|
return f[a] if pattern === a
end
end

我们使用 === 以便可以使用字符串或正则表达式。

使用方法如下:

p match('gnome')
# => "dwarf"

p match('dragon')
# => "run away!"
# => nil

p match('unicorn')
# => "equine unicorn"

p match('oddball')
# => false

你也可以用方法来做到这一点:

class Matcher

def match(a)
MATCHERS.each do |pattern, method|
return send(method, a) if pattern === a
end
end

private

MATCHERS = [
[/^gnome|dwarf|hobbit$/, :dwarf],
['dragon', :dragon],
[/^centaur|unicorn$/, :equine],
[//, :default],
]

def dwarf(a)
"dwarf"
end

def dragon(a)
puts "run away!"
end

def equine(a)
magical_equine_function(a)
end

def default(a)
false
end

def magical_equine_function(a)
"equine #{a}"
end

end

并在使用中:

matcher = Matcher.new
p matcher.match('gnome')
# => "dwarf"

# etc.

使用方法将代码与匹配规则分开,这样您就可以根据需要将匹配规则放在一个文件中。这是 match_rules 的内容:

---
- - !ruby/regexp /^gnome|dwarf|hobbit$/
- :dwarf
- - dragon
- :dragon
- - !ruby/regexp /^centaur|unicorn$/
- :equine
- - !ruby/regexp //
- :default

我们不需要对 Matcher 类做很多改变就可以让它工作:

require 'yaml'

class Matcher

def initialize
@matchers = YAML.load_file('match_rules')
end

def match(a)
@matchers.each do |pattern, method|
return send(method, a) if pattern === a
end
end

# ...

end

对文件中的数据使用send 允许创建该文件的人使您调用Matcher 类的任何方法。为了防止这种情况发生,您可以简单地为规则中使用的所有方法添加一个前缀:

def matched_dragon(a)
puts "run away!"
end

# etc.

然后在匹配方法中,添加前缀:

def match(a)
@matchers.each do |pattern, method|
return send("matched_#{method}", a) if pattern === a
end
end

现在匹配函数只能调用前缀为“matched_”的方法。


在评论中回答后续问题:

作为字符串数组的模式的 YAML 是这样的:

---
- - - gnome
- dwarf
- hobbit
- :small_person
- - - dragon
- :dragon

关于ruby - 将字符串近似匹配到列表并在 Ruby 中返回值的最简洁方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12990362/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com