【问题标题】:Postgresql and ActiveRecord where: Regex matchingPostgresql 和 ActiveRecord 其中:正则表达式匹配
【发布时间】:2014-04-02 00:56:14
【问题描述】:

我在普通正则表达式中创建了这个正则表达式

/(first|last)\s(last|first)/i

匹配前三个

first last
Last first
First Last
First name

我正在尝试获取 full_name 与我编写的正则表达式匹配的所有记录。我正在使用 PostgreSQL

Person.where("full_name ILIKE ?", "%(first|last)%(last|first)%")

这是我的尝试。我也试过 SIMILAR TO~ 没有运气

【问题讨论】:

    标签: ruby-on-rails regex postgresql activerecord rails-activerecord


    【解决方案1】:

    您的 LIKE 查询:

    full_name ilike '%(first|last)%(last|first)%'
    

    不起作用,因为 LIKE 不理解正则表达式分组 ((...)) 或交替 (|),LIKE 仅理解单个字符的 _(如正则表达式中的 .)和% 用于任何零个或多个字符的序列(如正则表达式中的 .*)。

    如果您将该模式交给 SIMILAR TO,那么您会找到 'first last',但由于案例问题,其他的都找不到;但是,这个:

    lower(full_name) similar to '%(first|last)%(last|first)%'
    

    将处理案例问题并找到与您的正则表达式相同的问题。

    如果您想使用正则表达式(您可能会这样做,因为 LIKE 非常有限且繁琐,而且 SIMILAR TO 是一些 SQL 标准小组委员会狂热的头脑的奇怪产品),那么您将想要使用不区分大小写的匹配运算符和您的原始正则表达式:

    full_name ~* '(first|last)\s+(last|first)'
    

    这转化为这一点 AR:

    Person.where('full_name ~* :pat', :pat => '(first|last)\s+(last|first)')
    # or this
    Person.where('full_name ~* ?', '(first|last)\s+(last|first)')
    

    您需要注意我的代码中有一个细微的变化:我对我的 Ruby 字符串使用单引号,而您使用的是双引号。反斜杠在双引号字符串中的含义比在单引号字符串中的含义更多,因此'\s'"\s" 是不同的东西。折腾几个to_sql 电话,你可能会看到一些有趣的东西:

    > puts Person.where('full_name ~* :pat', :pat => 'a\s+b').to_sql
    SELECT "people".* FROM "people"  WHERE (full_name ~* 'a\s+b')
    
    > puts Person.where('full_name ~* :pat', :pat => "a\s+b").to_sql
    SELECT "people".* FROM "people"  WHERE (full_name ~* 'a +b')
    

    这种差异可能不会给您带来任何问题,但是当每个人都想使用相同的转义字符时,您需要非常小心您的字符串。就个人而言,我使用单引号字符串,除非我特别需要双引号字符串的额外转义和字符串插值功能。

    一些演示:http://sqlfiddle.com/#!15/99a2c/6

    【讨论】:

    • 这是我在这里收到的最好的答案之一,谢谢。我不需要+,因为我很确定所有记录都只有一个空格。您使用符号:pat 的原因是将正则表达式定义为稍后正确的值?此外,如果我需要将多个值传递到 SQL 中,那么创建符号将有助于跟踪值。
    • 我使用 :pat 而不是 ? 使其更具可读性,这在只有一个占位符时并不重要,但在有更多占位符或您需要时它会起作用在多个地方使用相同的值。给事物命名是 IMO 的可读性胜利。无论如何,谢谢,我喜欢赚取积分,你向我学习的越多越好:)
    • 仅供参考:如果您使用的是 MySQL,~* 运算符不存在。相反,使用 REGEXP 代替它。
    • 谢谢,我必须使用 \\d 而不是 \d,而且当我使用单引号 Project.where('projectid ~* ?',"^(P#{(Date.today).year%100})\\d{5}$")时它也不起作用
    • @JoseKj 字符串插值仅适用于双引号,这可能需要双反斜杠来防止双引号尝试在 Ruby 中解释 \d,听起来对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 2020-05-01
    • 2013-09-22
    • 2015-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多