中文自然语言处理系列之一:正则匹配

作者: 施孙甲由 | 来源:发表于2019-03-03 15:06 被阅读273次

    本文汇总了部分中文自然语言处理中常用的,比较复杂的正则表达式,但并不是都是原创,部分引用了现有的网络资源,特此声明。

           相对其他语言的自然语言处理的领域,中文自然语言处理有其独特之处。即使是中文文本的处理,就有很多特有的处理细节。在中文文本处理时,经常需要用到许多正则表达式,而部分正则表达式的设计需要丰富的中文文本处理经验,才能在处理不同来源的文本时保持良好的性能。笔者收集了一些中文文本处理时常用的正则表达式,这些正则表达式都是经过精心设计的,性能也经过长期的测试验证,有着良好的实用效果。

    1. 邮箱地址

           邮箱地址一般可分为三个部分,用户名,@符号,以及邮箱服务的域名,形如:username@example.com,其中用户名的字符限制在大小写字母(a-zA-Z),数字(0-9),下划线(_),横线(-)以及英文句号(.),并开头必须是字母,而域名则至少有顶级域名及一级域名。因此邮箱地址的正则表达式需要考虑其组成结构以及用户名和域名的组成,其正则表达式如下:

    ([\w\d_\.\-]+)@([\w\d\-]+)(\.[\w\d\-]+)*(\.[\w\d]{2,6})
    

           邮箱地址的正则表达式的结构分解如下图所示:

    图1 邮箱地址的正则表达式的结构

    2. 手机号码

           对于国内手机号码的正则表达式,Github的项目ChinaMobilePhoneNumberRegex针对不同的需求,设计了对应的正则表达式,本文选取了该项目提供的匹配所有手机号码的正则表达式。而关于国内手机号码的详细说明可以参考维基百科的文章,此处只作简要的介绍。

           手机号码一般由十一位数字组成,有时还会加上国际区号,具体的组成如下表所示:

    位数 含义 说明
    - 国际区号 +86
    1~3位 网络识别号 手机运营商,每个运营商分配有不同的字段,都以1开头
    4~7位 地区编码 识别手机归属地
    8~11位 用户号码 随机分配

    网络识别号均是由特别的数字编号组成的,目前只有有限的数字编号,但不时会新增,具体可以参考维基百科的文章

           考虑国际区号,手机号码的正则表达式如下所示:

    (?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[35678]\d{2}|4(?:0\d|1[0-2]|9\d))|9[189]\d{2}|66\d{2})\d{6}
    

           同样给出手机号码的正则表达式的结构解析:

    图2 手机号码的正则表达式的结构

    3. URL

           URL相对比较复杂,要设计比较通用的URL匹配正则表达式确实是比较困难的事。无意中发现的一篇博文专门对URL的匹配正则表达式的设计进行了研究,分别给出了通用的URL匹配正则表达式和网站URL的匹配正则表达式,其中通用的URL正则表达式如下所示:

    ((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))
    

           博文同样给出了URL的匹配正则表达式的组成结构,具体说明如下:

    (                                             # 开始匹配整个URL
        (?:
            [a-z][\w-]+:                          # URL的协议及冒号
                (?:
                    /{1,3}                        # 1-3斜杠
                    |                             # 或者
                    [a-z0-9%]                     # 单个字母,数字或者百分号
                 )
            |                                     # 或者
            www\d{0,3}[.]                         # 万维网符号,如"www.","www1.", "www2." 等
            |                                     # 或者
            [a-z0-9.\-]+[.][a-z]{2,4}/            # 类似于域名加上斜杠
        )
        (?:                                       # 一个或多个组
            [^\s()<>]+                            # 没有空格以及-,(,),<,>中的任意一个字符
            |                                     # 或者
            \(([^\s()<>]+|(\([^\s()<>]+\)))*\)    # 两级括号对
         )+
         (?:                                      # URL结尾
             \(([^\s()<>]+|(\([^\s()<>]+\)))*\)   # 两级括号对
            |                                     #   或者
            [^\s`!()\[\]{};:'".,<>?«»“”‘’]        # 无空格及英文标点
         )
    )
    

           上述URL的正则表达式可用于URL的匹配,但如果需要对URL进行解析,可参考Github上的项目js-url

    4. 身份证号

           常见的身份证号码为十八位,但早期的身份证号码是十五位数,后来考虑到千年虫的问题,有添加了18位身份证的号码编制规则。其中十八位的身份证的组成如下表所示:

    含义 位数 约束
    省、自治区、直辖市代码 1~2位 起始数字不为0
    地级市、盟、自治州代码 3~4位 -
    县、县级市、区代码 5~6位 -
    出生年月日 7~14位 日期格式
    顺序号 15~17位 17位奇数为男,偶数为女
    校验码 18位 数字或者字母X

    十五身份号码与十八位身份证号码的区别有两处,其一是十五位身份证号码的年的编码只有两位,其二是没有最后的校验码,就比十八位的身份证少了三位数字。

           十八位身份证号码的匹配正则表达式如下:

    [1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]
    

    其结构分解如下图所示:

    图3 十八位身份证号码的正则表达式的结构

           十五位身份证号码的匹配正则表达式如下:

    [1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}
    

    其结构分解如下:

    图4 十五位身份证的正则表达式的结构

    将两个正则表达式结合在一起,便可得到最终完整的身份证的匹配正则表达式了。

           最后推荐几个调试正则表达式的网站:Regular Expressions 101RegExrDebuggex

    持续更新中

    相关文章

      网友评论

        本文标题:中文自然语言处理系列之一:正则匹配

        本文链接:https://www.haomeiwen.com/subject/fcizyqtx.html