【问题标题】:How to select records from mysql database by regex如何通过正则表达式从mysql数据库中选择记录
【发布时间】:2012-11-11 20:51:27
【问题描述】:

我有一个正则表达式来验证用户电子邮件地址。

/^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})$/i"

在活动记录的帮助下,我想从数据库中获取电子邮件地址与此正则表达式不匹配的所有用户。我尝试了以下scope 来达到预期的结果,但我得到的只是ActiveRecord::Relation

scope :not_match_email_regex, :conditions => ["NOT email REGEXP ?'", /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})$/"]

这给了我以下查询:

SELECT `users`.* FROM `users` WHERE (email REGEXP '--- !ruby/regexp /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\\-+)|([A-Za-z0-9]+\\.+)|([A-Za-z0-9]+\\++))*[A-Za-z0-9]+@((\\w+\\-+)|(\\w+\\.))*\\w{1,63}\\.[a-zA-Z]{2,})$/\n...\n')

我也尝试用以下方式定义这个scope,结果相同:

scope :not_match_email_regex, :conditions => ["email REGEXP '(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,})'"]

它生成的查询是:

SELECT `users`.* FROM `users` WHERE (email REGEXP '(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+.+)|([A-Za-z0-9]+++))*[A-Za-z0-9]+@((w+-+)|(w+.))*w{1,63}.[a-zA-Z]{2,})')

如何获取与给定正则表达式匹配或不匹配的所有记录?

【问题讨论】:

    标签: mysql ruby-on-rails ruby regex scope


    【解决方案1】:

    EDIT 12-11-30 部分根据@innocent_rifle 的评论进行小修正

    此处建议的正则表达式尝试与原始问题中的匹配项进行相同的匹配

    1. 在我第一次编写解决方案时,我忘记了您必须在字符串中转义 \,因为我是直接在 MySQL 中进行测试的。在讨论正则表达式时,在字符串中使用正则表达式会令人困惑,所以我将使用这种形式,例如/dot\./.source(在 Ruby 中)将提供 "dot\\."

    2. REGEXP in MySQL(5.6 的手册,在 5.0.67 中测试)正在使用“字符串中的 C 转义语法”,所以 WHERE email REGEXP '\.' 仍然与 WHERE email REGEXP '.' 相同,以找到字符"."你必须使用WHERE email REGEXP '\\.',要实现你必须使用代码.where([ 'email REGEXP ?', "\\\\."])。使用.where([ 'email REGEXP ?', /\\./.source ]) 更具可读性(MySQL 需要 2 次转义)。不过我更喜欢用.where([ 'email REGEXP ?', /[.]/.source ]),这样我就不用担心需要多少转义了。

    3.您不需要在正则表达式中转义"-",在[] 中使用时不需要转义,只要该字符是第一个或最后一个。


    我发现了一些错误:这是第一个正则表达式或“|”在你的表达中,它应该作为查询中的字符串,或者使用我更喜欢的 Regexp#source。我认为最后还有一个额外的报价。 除此之外,您真的确定正则表达式有效。如果你在控制台中对字符串进行尝试?

    另外请注意,您不会在 db 中捕获带有 NULL 的电子邮件,在这种情况下您必须添加 (<your existing expr in parentheses>) OR IS NULL

    我的 MySQL 版本中的正则表达式语法。

    我还测试了@Olaf Dietsche 在他的建议中写的内容,似乎不需要,但强烈建议遵循标准语法NOT (expr REGEXP pat)expr NOT REGEXP pat)。

    我做了一些检查,这些东西必须改变:使用[A-Za-z0-9_]而不是\w,并且\+无效,你必须使用\\+"\\\\+"如果是字符串),更容易用@ 987654342@(在正则表达式或字符串中)。

    这会导致在 MySQL 中跟随 REGEXP

    '^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]+)|([A-Za-z0-9]+[+]+))*[A-Za-z0-9]+@(([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]))*[A-Za-z0-9]{1,63}[.][a-zA-Z]{2,}$'
    

    小改动建议

    我不完全理解你的正则表达式,所以这只是改变你的正则表达式而不改变它会找到的内容。

    首先:按照我上面的描述更改整个字符串

    然后改变

    (([A-Za-z0-9]+_+)|([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]+)|([A-Za-z0-9]+[+]+))*
    

    ([A-Za-z0-9]+[-+_.]+)*
    

    @(([A-Za-z0-9]+-+)|([A-Za-z0-9]+[.]))*
    

    @([A-Za-z]+[-.]+)*
    

    最终代码(如果您愿意,请更改为 ..., :conditions => ...syntax)。 我试图让它找到与@innocent_rifle 评论中相同的字符串,只在@ 右侧的表达式中添加"_"

    .where([ 'NOT (email REGEXP ?)', /^([A-Za-z0-9]+[-+_.]+)*[A-Za-z0-9]+@([A-Za-z0-9]+[-._]+)*[A-Za-z0-9_]{1,63}[.][A-Za-z]{2,}$/.source ])
    

    【讨论】:

    • 好吧,最后我设法通过几次更正使它工作。我不得不逃避所有的反斜杠。以下正则表达式适合我:Users.where("NOT email REGEXP '^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\\-+)|([A-Za-z0-9]+\\.+)|([A-Za-z0-9]+\\\\++))*[A-Za-z0-9]+@(([a-zA-Z0-9]+\\-+)|([a-zA-Z0-9]+\\.))*[a-zA-Z0-9]{1,63}\\.[a-zA-Z]{2,}'")。请添加一些更正以回答。
    • 好的,我已经更改了一些我的建议。很抱歉错过了“\”,我也评论过,这是因为我直接在 MySQL 中测试。现在我已经直接在 MySQL 中进行了测试,也从控制台进行了测试。我还评论说,如果您在 Ruby 代码中使用 "REGEXP '\\.'",则在 MySQL 中使用时只有一次转义,而 MySQL 需要 2 次转义,在 MySQL REGEXP 中 \.. 相同。
    【解决方案2】:

    对于验证电子邮件地址,您可能需要考虑How to Find or Validate an Email Address。至少,这个正则表达式看起来更简单一些。

    根据MySQL - Regular Expressions,正确的语法是

    expr REGEXP pat

    匹配,并且

    expr NOT REGEXP patNOT (expr REGEXP pat)

    相反。不要忘记第二个版本中的大括号。

    【讨论】:

    • 我测试了NOT expr REGEXP pat(不带括号),它似乎工作,也许它只适用于我的MySQL版本(不知道如何检查服务器上的哪个版本 - 尴尬)。但无论如何,知道正确的语法是件好事 - 谢谢。
    • @244an 我自己没有测试过,但是mysql网站上是这样描述的。因此,遵循它并保持安全并没有什么坏处。
    • “很高兴知道”我的意思是“会这样做”,遵循语法并没有什么坏处,但如果你不这样做肯定会受到伤害。将来的版本可能会发生变化,如果您没有遵守所有规则,则可能会出现错误。所以,再一次,很高兴知道:)
    猜你喜欢
    • 2015-08-28
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    相关资源
    最近更新 更多