Java 中用正则表达式修改 Email 地址

需求

系统中有一列会用来存储 email 地址,现在需要对输入的字符串进行过滤,
要求是,把无效的地址过滤掉。有一些需要说明的是

  1. 这些地址是通过图像识别得到的,有些是用户自己输入的
  2. 已有历史记录已经存在了脏数据,需要替换
  3. 这个地址是识别出来的,不是用户帐号和联系信息这样的关键数据。所以宁愿相信用户是手误多录入的字符,或是机器识别把不该记录的字符当成 Email 的一部分了

测试字符串:

String[] arrEmailAddr = new String[]{
    "\uD83D\uDC02abc123@cc.cc",
    "A78=B[咔嚓]C⌚️2345@cc.cc",
    "abc\uD83C\uDF32'sdfsd@sdfsd.·」cc",
    "a·「d(*^@cc.cc",
    "asl'''fgjk&^*'\"234@sgd_slgkj-sdfsd.com"
};

方案和坑

本以为用了很多年正则,已经很熟练了,应该信手拈来,没想到实际操作时居然遇到那么多坑

首先可以确定的是,使用 Java 的 ReplaceAll 是没错了

  1. 网上广为流传的神 Pattern

    // 清除掉所有特殊字符 
    String regEx="[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";   
    
    Pattern p = Pattern.compile(regEx); 
    
    Matcher m = p.matcher(str);  
    
    return m.replaceAll("").trim();
    

    首先,我是十分讨厌这种穷举法的;其次,对层出不穷的特殊字符控制不足,比如全角空格、颜文字等等。

    pass

  2. 按照 Email 的格式严格匹配,把不符合 Email 格式的直接替换掉
    是个比较彻底的方法,但是,实际操作前,发现有这样一些让人无语的脏数据:

    +--------+----------------------------------------------------+
    | id     | email                                              |
    +--------+----------------------------------------------------+
    |  66898 | 信箱三-mail:zhixxxxxxxxxx@163.com                  |
    | 115764 | 邮箱:1xxxxxx890@qq.com                             |
    | 513557 | M0:svxxxxxx@vip.163.c0m                            |
    | 708165 | 邮箱:lixxxxxxxx@zjlcwg.com                         |
    | 966373 | Mail:chenxxxxxx@ch-jht.com                         |
    +--------+----------------------------------------------------+
    5 rows in set (0.05 sec)
    
    

    这些记录不在少数,肯定需要保留。
    所以,问题还是回到 替换 这条思路上来

  3. 使用白名单
    实际上只能这么做,难点和坑也在于这里,先列几个我犯的错误示例:

    String regEx = "/[0-9a-z]/"; // 这是一个正向测试,不过测试本身就有问题,Java里面不是用 “/” 来标识两端的  
    
    String regEx="[^0-9][^a-z][^_]"; // 这样会顺序匹配,在每个匹配组上干掉了其他组的合法字符  
    
    String regEx="(\\W|@|-....)"; // 匹配到第一个之后,就直接过滤掉了,后面的其他字符不会被保留
    
    String regEx="^[a-z0-9-_@]"; // ^ 字符匹配的是字符串开始的地方,无法作为 “非” 来使用,加转译就更不对了
    
    String regEx="[^0-9a-z.-_@]"; // 这个就坑大了,自己看结果:
    
    /** -----
    abc123@cc.cc
    A78=B[]C2345@cc.cc
    abcsdfsd@sdfsd.cc
    ad^@cc.cc
    aslfgjk^234@sgd_slgkjsdfsd.com
    ---- */
    // 问题在于,“.” 这个字符,在里面会被认为是任意字符的匹配,对反斜线“免疫”
    

最终结果

测试字符
见文首

正则源码
正如上文说的,“.” 字符必须放末位

// 与下面的等价 String regEx="[^0-9a-z-_@.]";
String regEx="[^\\w-@.]";

输出

abc123@cc.cc
782345@cc.cc
abcsdfsd@sdfsd.cc
ad@cc.cc
aslfgjk234@sgd_slgkj-sdfsd.com

posted @ 2018-12-27 16:33  风在山路吹  阅读(387)  评论(0编辑  收藏  举报