2

我有 Ruby on Rails 应用程序,它有一个映射到 People 表的 Person 模型。该表包括 first_name、middle_name 和 last_name,如下所示:

John Q. Doe
John H. Doe
Jane M. Doe
Jim R. Doe, Jr.
Jack Timothy Doe

现在,当我的输入是特定名称派生的缩写时,我需要对表执行查找。缩写形式如下:

  • 名字的第一个首字母后跟一个空格
  • 中间名的首字母后跟一个空格(如果有中间名)
  • 全名

例如:

find_by_abbreviated_name("J Q Doe") => would find the John Q. Doe record
find_by_abbreviated_name("J T Doe") => would find the Jack Timothy Doe record
find_by_abbreviated_name("J R Doe, Jr.") => Jim R Doe, Jr.

Ruby 中是否有一种巧妙的方法可以使用名字和中间名的第一个字母以及完整的姓氏进行查找。我希望我能想出一种方法来做到这一点,这样我就不必在 Person 表中添加另一个字段。

4

3 回答 3

2

所以我认为你必须处理的问题是输入的格式会有所不同......除非你能保证输入元素。如果 middle 是可选的,并且 last 可能有多个标记,那么您有一个挑战,如果它作为单个字符串传递,您将无法可靠地解析:

John Doe Jr
John Doe, Jr.
John Quentin Doe
John Doe Worthington-Smythe

(许多姓氏有多个部分等)

因此,您可以通过提供不同的输入字段、与用户确认模棱两可的情况或根据某些规则或常见情况尝试几种替代方案来处理此问题。所以让我们等待解析部分并假设您有不同的输入格式正确(例如大写的单个字符):

def find_by_abbreviated_name(fist_init, middle_init, last_name)
  if middle_init.blank?
    People.where("first LIKE ? AND middle LIKE ? and LAST like ?", "#{first_init}%", "#{middle_init}%", "#{last_name}%")
  else
    People.where("first LIKE ? AND LAST LIKE ?", "#{first_init}%", "#{last_name}%")
  end
end

这将导致 SQL 使用 LIKE 运算符,这是一个部分匹配 - 这%是一个 SQL 通配符,类似于*文件名匹配或正则.*表达式。

抱歉,我的前三个尝试有错误。我现在正在检查是否有办法更好地使用通配符......

于 2012-11-19T01:09:31.340 回答
1

这个问题是使用字符串排名算法的理想选择!

看看这个使用 Jquery / Prototype 实现的 Quicksilver 算法。

基本上,就像其他人已经提到的那样,这样做很痛苦,因为您不能总是考虑输入数据的格式。

我不相信有一个活跃的 gem 或 ruby​​ 端口,但它相当简单。

在 Rails 应用程序中实现这一点意味着

  1. 获取所有人的 id 和串联名称
  2. 在该数组上运行算法
  3. 根据排序数组中的 id 获取前 1/3/n 行。

我个人避免过于频繁地“构建”查询,AR 作为 ORM 对我来说还不够强大。但是,如果您要走那条路,则绝对应该检查Squeel gem失败,其中 AREL 是必须的。

于 2012-11-19T07:18:41.140 回答
1

没有光滑的 Ruby 方式。您只需要构建一个查询。像这样的东西应该工作:

def self.find_by_abbreviated_name(name)
  if name[3].blank? && name.size >= 5 # Check if there's a middle initial
    where("first_name like ? and middle_name like ? and last_name = ?", "#{name[0]}%", "#{name[2]}%", name[4..-1])
  else # No middle initial
    where("first_name like ? and last_name = ?", "#{name[0]}%", name[2..-1])
  end
end

解释:

仅当字符串的格式始终相同时,名称字符串的“技巧”才有效。name[0]给出字符串的第一个字符,name[2]给出第三个字符name[4..-1]并将第五个字符返回到字符串的末尾。

我认为该where条款本身非常简单。要仅根据第一个字符查找记录,您可以使用: .where('field_name like ?', "#{query}%"),其中问号确实是替换值的占位符。

编辑:

对于省略中间首字母的情况,我更新了我的答案。

于 2012-11-19T00:57:51.950 回答