Python中的正则表达式

Python中的正则表达式

概述

python中:编码:unicode-->str   解码:str-->Unicode

 

在python中,编码函数是encode(),解码函数是decode()。

 

【需要注意的一点是,如果我们调用str.encode(),这里涉及到一个隐士的类型转化,会现将str转化成unicode,才能进行编码,这也是不太容易理解的地方。所以,str.encode()实际上就等价于str.decode(sys.defaultencoding).encode().而sys.defaultencoding一般是ascii,它是不能用来编码中文字符的。】

 

各种编码方式

Python中,不论是Python 2.x还是Python 3.x中,总体上说,字符都只有2大类:

一类是通用的Unicode字符;另一类是,(unicode被编码后的),某种编码类型的字符,比如UTF-8GBK等等类型的字符】

 

 

ASCII(American Standard Code forInformation Interchange),是单字节编码,一个字节等于8位二进制数,所以单字节可以表示256个不同的字符,可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半(\x80以下)。

 

MBCS(Multi-Byte Character Set) ,这一类编码有很多种,其中就有GBK:为了表示其他语言的字符,采用双字节编码,并且兼容ASCII,采用的方式是:如果第一个字节是\x80以下,则仍然表示ASCII字符;而如果是\x80以上,则跟下一个字节一起(共两个字节)表示一个字符,然后跳过下一个字节,继续往下判断。

 

后来的后来·····人们为了方便统一了编码方式··unicode

Unicode的编码方式的标准用很多:【UCS-2(两个字节表示一个字符)】【UTF-8变长的,并且兼容ASCIIASCII字符使用1字节表示,其他符号用更多编码方式匹配

 

By the way : BOM(Byte Order Mark)是一种标记,就是在我们打开记事本的时候,最开始读入的是什么编码,我们就按这种编码方式打开整个文本,这就是为什么我们不用在打开记事本的时候先选择编码方式··

 

str字节串,是它是unicode经过编码后的字节组成的序列。

例如unicode 中的“水”字,经过UTF-8编码后得到的str为“\xe6\xb0\xb4len()==3

Python中用中文字符串前面加上u表示这个字符串为unicode

 

unicode字符串,对str进过正确解码可以获得 ,对于(u“水”)len()==1

 

 

具体操作

"python 2.x中,普通的,用引号括起来的字符,就是str;此时字符串的编码类型,对应着你的Python文件本身保存为何种编码有关,最常见的Windows平台中,默认用的是GBK"

 

str->unicode:  需要解码的str.decode(解码方式【例如:‘UTF-8‘)

 

 

unicode->str  先声明一个Unicode字符unicodechar,例如【u‘水’】,unicodechar.encode(编码对应的方式【例如:‘UTF-8‘)

 

 

by the way: python 3.x,具体操作有很大区别

 

 

字符码的声明:源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:

 

#-*- coding: UTF-8 -*-


实际上Python只检查#coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8

 

 

关于文件操作

内置的open()方法打开文件时,read()读取的是str

write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()

如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。

 

另外,模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。

 

Tips:

1.   使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明

2.   抛弃str,全部使用unicode

 

深入

正因为中文字符需要多个字节来表示,常见的正则表达式的文档就有可能无法覆盖这种情况。比如常见的资料都说,点号『.』可以匹配“除换行符\n之外的任意字符”,但这可能只适用于“单字节字符

 

re.search(‘^.$‘, ‘发‘) == None #True


 

之所以会出现这种情况,是因为正则表达式无法正确将多个字节识别为“单个字符”

如果你细心就会发现,在Python 2.x中,我们指定的字符串使用Unicode编码,而文档里说了,正则表达式也可以指定Unicode模式的

 

正则表达式的操作可以简要概括为“用正则表达式去匹配字符串”,它涉及两个对象:正则表达式和字符串。

 

对字符串来说,如果没有设定Unicode模式,则多字节字符很可能会拆开为多个单字节字符对待(虽然它们并不是合法的ascii字符),Python 2.x中就是如此,“发”字在没有设定Unicode编码时,变成了3个单字节字符构成的字符串,点号『.』只能匹配其中的单个“字符”。如果显式将正则表达式设定为Unicode字符串(也就是在 u‘发‘ ),则“发”字视为单个字符,点号可以匹配。

 

那么对应的,如果你在正则表达式的字符组里使用了中文字符,表示正则表达式的字符串,也应该设定为Unicode字符串,否则正则表达式会认为字符组里不是单个字符

 

>>> re.search(‘^[我]$‘, u‘我‘) == None # True

>>> re.search(u‘^[我]$‘, u‘我‘) == None # False 


 

 

Python也可以指定正则表达式使用Unicode模式

 

不妨回头仔细想想你读过的文档,正则表达式中的『\d』和『\w』,都是如何解释的?或许你的第一反应是:『\d』等价于『[0-9]』,『\w』等价于『[0-9a-zA-Z_]』。因为有些文档说明了这种等价关系,有些文档却说:『\d』匹配数字字符,『\w』匹配单词字符。然而这只是针对ascii编码的规定,在Unicode编码中,全角数字0、1、2之类,应该也可以算“数字字符”,由『\d』匹配;中文的字符,应该也可以算“单词字符”,由『\w』匹配;同样的道理,中文的全角空格,应该也可以算作“空白字符”,由『\s』匹配。所以,如果你在Python中指定了正则表达式使用,『\d』、『\w』、『\s』就能匹配全角数字、中文字符、全角空格。

 

(字符均为全角)

>>> re.search(‘(?u)^\d$‘, u‘1‘) == None # True 

>>> re.search(‘(?u)^\w$‘, u‘发‘) == None # True 

>>> re.search(‘(?u)^\s‘, u‘ ‘) == None # True 


 

如果上面的数字用半角,

re.search(‘(?u)^\d$‘, u‘1‘) == None # False


 
 
 
参考博文:
http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html
 
http://www.crifan.com/summary_python_string_encoding_decoding_difference_and_comparation_python_2_x_str_unicode_vs_python_3_x_bytes_str/
 
http://www.infoq.com/cn/news/2011/02/regular-expressions-unicode/
 

Python中的正则表达式

上一篇:python + selenium2library 自动化框架


下一篇:Programming Python - 1. Preview -1.3 Stepping up to OOP