2014年7月31日星期四

python中的正则表达式与unicode

正则表达式作为一种最常用的工具,在平常的工作中使用的非常普遍,在python中是由re库提供这个功能,除此之外还有regex库提供额外的功能。
在一般的正则表达式介绍中都是以ascii为代表来介绍的,但是作为一个中国的程序员,所遇到的一个最基本的问题就是字符编码了。所以这里说下如何在python中匹配
非ascii字符。

正则表达式是使用一个模式串来找出所有可以用模式串描述的字符串,模式串由普通字符跟元字符组成,这就是正则表达式最核心的想法。在一个模式串中,
普通字符是用于匹配,而元字符则可以看成是在普通字符上的施加的一种操作或者是函数。既然如此,非ascii字符对正则表达式的影响就集中在普通字符这一块而不是
元字符。而普通字符是由整数值表示的,匹配则意味着在模式串中的整数值跟在目标串中的整数值相等,如果在目标串跟模式串中使用了不同的字符编码,很明显,他
们是不能匹配的。因此在使用正则表达式用于匹配非ascii字符时,需要保持模式串跟目标串的编码一致。如下所示:

Snip20121230 2
当模式串的字符编码跟目标串一致的时候就能够成功的匹配。如果你的模式串中只有普通字符,那么这样就可以满足你的要求了。但是问题没有这么简单,当你试图用元字符的时候就会出现问题,示例如下:
Snip20130129 2
这里我们的模式串是'人生{2,}',想要匹配的字符串是有一个“人”和至少两个“生”,但是从匹配的结果来看,这个正则表达式并没有达到我们的目的。问题还是在于编码,'人生{2,}'的GB18030编码是'\xc8\xcb\xc9\xfa{2,}',因此这个正则表达式的意思就是匹配至少一个'\xc8\xcb\xc9'和至少两个'\xfa',和我们表达的意思完全按不同,原因在于一个汉字字符使用了多个字节的表示,而元字符+只作用在最后一个字节上。对于这种问题的解决方案也很简单,就是寻找一个能够将汉字字符表示为数字的编码,而不是使用多个数字来组合表示,也就是一种内部统一的表示。但是我现在又想到了一个问题,任何一个字符编码最终都是一个字节一个字节的,因为计算机最基本的存储单位就是字节,所以这个问题在于字符串比较函数的问题,没有办法将多个相关的字节识别成一个整体,才导致这个问题的。然后我们看到如果使用python内部的字符表示,那么就没有什么问题!

在这里使用Unicode能够解决问题,但是Unicode带来的编码却不止于此,因为如果把可以识别的字符从ASCII扩大到Unicode,那么有些表示就需要重新定义了,比如\d,\w,\s等等。这里就以\w为例来演示Unicode的影响。
Snip20130129 3
这里(?u)就是启用Unicode dependent特性,可以看到在未启用这个特性之前,使用正则表达式\w+不能匹配到任何的字符串,但是使用这个特性,那么就可以匹配到全部的汉字。其实在Unicode中,每个字符除了对应一个码点(也就是一个数字),还有对应的属性,可以在正则表达式中使用属性来进行匹配,比如属性为汉字什么的,还是很方便的。

没有评论:

发表评论