【问题标题】:Using SQL REGEXP to find mobile number使用 SQL REGEXP 查找手机号码
【发布时间】:2012-11-08 07:06:02
【问题描述】:


我们的数据库可以包含不同格式的手机号码,例如:“(731) 123-4567”或“731-123 45 67”或“731-12-3-[4567]”等。
此外,我在搜索 API 中获得的输入可以是任何格式。
因此,当我需要在 db 中查找具有移动设备的用户时,我会清理输入数字,使其看起来像“7311234567”,然后用正则表达式 '(\\+|\\-|\\(|\\)|\\[|\\]| )*' 包装/填充它,例如,SQL 看起来像这样:

select * from contact where mobile REGEXP '(\\+|\\-|\\(|\\)|\\[|\\]| )*
             1(\\+|\\-|\\(|\\)|\\[|\\]| )*7(\\+|\\-|\\(|\\)|\\[|\\]| )*
             3(\\+|\\-|\\(|\\)|\\[|\\]| )*1(\\+|\\-|\\(|\\)|\\[|\\]| )*
             2(\\+|\\-|\\(|\\)|\\[|\\]| )*9(\\+|\\-|\\(|\\)|\\[|\\]| )*
             8(\\+|\\-|\\(|\\)|\\[|\\]| )*0(\\+|\\-|\\(|\\)|\\[|\\]| )*
             7(\\+|\\-|\\(|\\)|\\[|\\]| )*4(\\+|\\-|\\(|\\)|\\[|\\]| )*
             0(\\+|\\-|\\(|\\)|\\[|\\]| )*';

问题是,当我得到像“11234567”这样的输入时,它就像“7311234567”但没有“73” - 当查询执行时 - 它还会找到具有“7311234567”的用户。

问题:如何更好地包装我的正则表达式,使其仅适合正则表达式的完整数字?

【问题讨论】:

  • 您是否尝试过删除任何非数字字符并比较两者?
  • @Alex - 我无法控制数据库中保存的数字。假设它们可以是任何格式,这就是我选择正则表达式解决方案的原因,但我不确定如何添加到正则表达式长度的精确匹配。 10x

标签: java mysql sql database


【解决方案1】:

这样的东西会起作用吗?它使用REPLACE 而不是REGEX,但它似乎符合您的要求(是的,这有点恶心 - 请参阅 SQLFiddle here 以获得更清晰的视图)。您可以根据需要添加更多参数以进一步标记:

SET @num = '7311234567';

SELECT *
FROM mobile
WHERE 
  REPLACE(
    REPLACE(
      REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(num, ' ', ''), '-', ''), '(', ''), ')', ''), '[', ''), ']', '')

  = 
  REPLACE(
    REPLACE(
      REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(@num, ' ', ''), '-', ''), '(', ''), ')', ''), '[', ''), ']', '')

【讨论】:

  • 谢谢,这似乎可行,但是 REPLACE(尤其是嵌套的 REPLACE)与 REGEXP 之间的性能差异如何?
  • @urir 绝对是要进行基准测试的东西 - 实际上我自己不必使用此设置。与上述 UDF 方法相比,我的解决方案可能会更慢(这似乎是一个强大的包,我随时都会将他们的技能置于我之上:))。
【解决方案2】:

您可以使用此MySQL package 以便让regexp_replace 供您使用。 然后可以在搜索的时候替换所有非数字字符,避免不同格式的测试。

String mobileInput = "(731) 123-4567";
String mobile = mobileInput.replaceAll("[^0-9]", "");

String sql = "select * from contact where regexp_replace(mobile, '[^0-9]', '') = ?";
// run your sql query

// or directly on database side without Java
String sql = "select * from contact where regexp_replace(mobile, '[^0-9]', '') = regexp_replace(?, '[^0-9]', '')";

通过删除非数字字符,(731) 123-4567731-123 45 67731-12-3-[4567] 将为您提供 7311234567

用 Oracle 测试,因为我没有安装 MySQL:

select regexp_replace('(731) 123-4567', '[^0-9]', '') as "first",
       regexp_replace('731-123 45 67', '[^0-9]', '') as "second",
       regexp_replace('731-12-3-[4567]', '[^0-9]', '') as "third"
  from dual

->

     first          second           third
7311234567      7311234567      7311234567

【讨论】:

  • 这将是最好的解决方案String sql = "select * from contact where regexp_replace(mobile, '[^0-9]', '') = ?"; 但如果我理解正确 - 我需要在我的数据库上安装这个包。对吗?
  • 是的,您必须将其安装在本地数据库中。你可以按照这个应该有点相似的指南:mysqludf.org/lib_mysqludf_preg。您必须将 C 源代码编译到共享对象库 *.so 中,然后告诉 mysql 在哪里找到这些新函数。有关在 MySQL 上编译/安装 UDF 的信息,请参见官方页面:dev.mysql.com/doc/refman/5.1/en/udf-compiling.html
  • 谢谢,我不确定它现在是否会通过......看起来我更喜欢“REPLACE”。
【解决方案3】:

如果您不想为此安装额外的软件包,您只需在您的正则表达式中添加开始和结束锚点:^$

您还可以将其简化为不那么冗长:

^[^0-9]*7[^0-9]*3[^0-9]*1[^0-9]*1[^0-9]*2[^0-9]*3[^0-9]*4[^0-9]*5[^0-9]*6[^0-9]*7[^0-9]*$

当然,最好的解决方案是规范化输入数据。

【讨论】:

  • 嗨,我不确定我是否理解这一点。您将如何构建查询以搜索“7311234567”? 10 倍!
  • 和你做的一样:在每个数字之间加上[^0-9]*,并在开头和结尾加上^$
  • 效果很好 :) 并且是满足我需求的最干净的解决方案。非常感谢,Uri。
猜你喜欢
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 2022-10-15
相关资源
最近更新 更多