python2.7 中字符串前缀r与u

来源:互联网 发布:淘宝客推广大师手机板 编辑:程序博客网 时间:2024/06/05 23:50

U是Unicode的编码,r是原始字符

在python2.7.13版本中,默认编码格式为ASCII格式的
代码如下
1import sys
2print sys.getdefaultencoding()
Python的自带编辑器IDLE或者python Shell在默认情况下都不支持中文编码,若在脚本程序中出现中文,则会出现一定的错误。

原因:
因为Python脚本编码默认是ASCII编码的,当需要非ASCII编码的字符出现在脚本程序中时,需要添加相应的编码声明.

(1)以r或R开头的python中的字符串表示(非转义的)原始字符串
python里面的字符,如果开头处有个r,比如:
(r’^time/plus/\d{1,2}/$’, hours_ahead)
说明字符串r”XXX”中的XXX是普通字符。
有普通字符相比,其他相对特殊的字符,其中可能包含转义字符,即那些,反斜杠加上对应字母,表示对应的特殊含义的,比如最常见的”\n”表示换行,”\t”表示Tab等。
而如果是以r开头,那么说明后面的字符,都是普通的字符了,即如果是“\n”那么表示一个反斜杠字符,一个字母n,而不是表示换行了。
example:
f = open(r'C:\ProgramFiles\Adobe\Reader.txt','r')
(2)以u或U开头的字符串表示unicode字符串
Unicode是书写国际文本的标准方法。如果你想要用非英语写文本,那么你需要有一个支持Unicode的编辑器。
类似地,Python允许你处理Unicode文本——你只需要在字符串前加上前缀u或U。
example:
u"This is a Unicode string."

中文字符乱码问题(为正确再现被编码的原始文本,必须确保所编码数据与其编码声明一致。因为数据本身可被操纵,编码声明可被改写,两者不一致时必然产生乱码。

乱码常见于文本数据被声明为错误的编码,或不加编码声明就在默认编码不同的计算机之间传输。例如,通信协议依赖于每台计算机的编码设置,而不是与数据一起发送或存储元数据。)
乱码(mojibake)是指以非期望的编码格式解码文本时产生的混乱字符,通常表现为正常文本被系统地替换为其他书写系统中不相关的符号。

乱码原因及解决方案

未指定编码格式

若未指定编码格式,则由软件通过其他手段确定,例如字符集配置或编码特征检测

错误指定编码格式

错误指定编码格式时也会出现乱码,这常见于相似的编码之间。

过度指定编码格式

多层协议中,当每层都试图根据不同信息指定编码格式时,最不确定的信息可能会误导接受者。

解决方法

应用程序使用UTF-8作为默认编码时互通性更高,因为UTF-8使用广泛且向后兼容US-ASCII。UTF-8可通过简单的算法直接识别,因此设计良好的软件可以避免混淆UTF-8和其他编码。
现代浏览器和字处理器通常支持许多字符编码格式。浏览器通常允许用户即时更改渲染引擎的编码设置,而文字处理器允许用户打开文件时选择合适的编码。这需要用户进行一些试错,以找到正确的编码。
当程序支持的字符编码种类过少时,用户可能需要更改操作系统的编码设置以匹配该程序的编码。然而,更改系统范围的编码设置可能导致已存在的程序出现乱码。在Windows XP或更高版本的系统中,用户可以使用Microsoft AppLocale,以改变单个程序的区域设置。
当然,出现乱码时用户也可手工或编程恢复原始文本,详见本文”2.5 处理中文乱码”节,或《Linux->Windows主机目录和文件名中文乱码恢复》一文。

Python举例

coding=utf-8

import sys, localedef SysCoding():fmt = '{0}: {1}'#当前系统所使用的默认字符编码print fmt.format('DefaultEncoding    ', sys.getdefaultencoding())#转换Unicode文件名至系统文件名时所用的编码('None'表示使用系统默认编码)print fmt.format('FileSystemEncoding ', sys.getfilesystemencoding())#默认的区域设置并返回元祖(语言, 编码)print fmt.format('DefaultLocale      ', locale.getdefaultlocale())#用户首选的文本数据编码(猜测结果)print fmt.format('PreferredEncoding  ', locale.getpreferredencoding())#解释器Shell标准输入字符编码print fmt.format('StdinEncoding      ', sys.stdin.encoding)#解释器Shell标准输出字符编码print fmt.format('StdoutEncoding     ', sys.stdout.encoding)if __name__ == '__main__':   SysCoding()    

在源代码文件中,若字符串常量包含ASCII(Python脚本默认编码)以外的字符,则需要在文件首行或第二行声明字符编码,如#-- coding: utf-8 --。实际上,Python只检查注释中的coding: name或coding=name,且字符编码通常还有别名,因此也可写为#coding:utf-8或#coding=u8。

若不声明字符编码,则字符串常量包含非ASCII字符时,将无法保存源文件。若声明的字符编码不适用于非ASCII字符,则会触发无效编码的I/O Error,并提示保存为带BOM的UTF-8文件 。保存后,源文件中的字符串常量将以UTF-8编码,无论编码声明如何。而此时再运行,会提示存在语法错误,如”encoding problem: gbk with BOM”。所以,务必确保源码声明的编码与文件实际保存时使用的编码一致。

此外,源文件里的非ASCII字符串常量,应采用添加Unicode前缀的写法,而不要写为普通字符串常量。这样,该字符串将为Unicode编码(即Python内部编码),而与文件及终端编码无关。参考如下实例:

#coding: u8
print u'汉字', unicode('汉字','u8'), repr(u'汉字')
print '汉字', repr('汉字')
print '中文', repr('中文')
import sys
si = raw_input('汉字$')
print si, repr(si),
print si.decode(sys.stdin.encoding),
print repr(si.decode(sys.stdin.encoding))

读写在写入磁盘文件或通过套接字发送前,通常需要将Unicode数据转换为特定的编码;从磁盘文件读取或从套接字接收的字节序列,应转换为Unicode数据后再处理。

这些工作可以手工完成。例如:使用内置的open()方法打开文件后,将read()读取的str数据,按照文件编码格式进行decode();write()写入前,将Unicode数据按照文件编码格式进行encode(),或将其他编码格式的str数据先按该str的编码decode()转换为Unicode数据,再按照文件编码格式encode()。若直接将Unicode数据传入write()方法,Python将按照源代码文件声明的字符编码进行encode()后再写入。
这种手工转换的步骤可简记为”due”,即:
1) Decode early(将文件内容转换为Unicode数据)
2) Unicode everywhere(程序内部处理都用Unicode数据)
3) Encode late(存盘或输出前encode回所需的编码)
然而,并不推荐这种手工转换。对于多字节编码(一个Unicode字符由多个字节表示),若以块方式读取文件,如一次读取1K字节,可能会切割开同属一个Unicode字符的若干字节,因此必须对每块末尾的字节做错误处理。一次性读取整个文件内容后再解码固然可以解决该问题,但这样就无法处理超大的文件,因为内存中需要同时存储已编码字节序列及其Unicode版本。
解决方法是使用codecs模块,该模块包含open()、read()和write()等方法。其中,open(filename, mode=’rb’, encoding=None, errors=’strict’, buffering=1)按照指定的编码打开文件。若encoding参数为None,则返回接受字节序列的普通文件对象;否则返回一个封装对象,且读写该对象时数据编码会按需自动转换。
Windows记事本以非Ansi编码保存文件时,会在文件开始处插入Unicode字符U+FEFF作为字节顺序标记(BOM),以协助文件内容字节序的自动检测。例如,以utf-8编码保存文件时,文件开头被插入三个不可见的字符(0xEF 0xBB 0xBF)。读取文件时应手工剔除这些字符:

import codecsfileObj = codecs.open(r'E:\PyTest\data_utf8.txt', encoding='utf-8')uContent = fileObj.readline()print 'First line +', repr(uContent)#剔除utf-8 BOM头uBomUtf8 = unicode(codecs.BOM_UTF8, "utf8")print repr(codecs.BOM_UTF8), repr(uBomUtf8)if uContent.startswith(uBomUtf8):        uContent = uContent.lstrip(uBomUtf8)print 'First line -', repr(uContent)fileObj.close()

处理中文乱码

本节主要讨论编码空间不兼容导致的中文乱码。

乱码可能发生在print输出、写入文件、数据库存储、网络传输、调用shell程序等过程中。解决方法分为事前事后:事前可约定相同的字符编码,事后则根据实际编码在代码侧重新转换。例如,简体中文Windows系统默认编码为GBK,Linux系统编码通常为en_US.UTF-8。那么,在跨平台处理文件前,可将Linux系统编码修改为zh_CN.UTF-8或zh_CN.GBK。
关于代码侧处理乱码,可参考一个简单的乱码产生与消除示例:
example:

#coding=gbks = '汉字编码'print '[John(gb2312)] Send:    %s(%s) --->' %(s, repr(s))su_latin = s.decode('latin1')print '[Mike(latin1)] Recv:    %s(%s) ---messy!' %(su_latin, repr(su_latin))

其中,John向Mike发送gb2312编码的字符序列,Mike收到后以本地编码latin1解码,显然会出现乱码。假设此时Mike获悉John以gb2312编码,但已无法访问原始字符序列,那么接下来该怎么消除乱码呢?根据前文的字符编码基础知识,可先将乱码恢复为字节序列,再以gbk编码去”解释”(解码)该字符序列,即:

s_latin = su_latin.encode('latin1')print '[Mike(latin1)] Convert  (%s) --->' %repr(s_latin)su_gb = s_latin.decode('gbk')print '[Mike(latin1)] to gbk:  %s(%s) ---right!' %(su_gb, repr(su_gb))

可见,乱码消除的步骤为:1)将乱码字节序列转换为Unicode字符串;2)将该串”打散”为单字节数组;3)按照预期的编码规则将字节数组解码为真实的字符串。显然,”打散”的步骤既可编码转换也可手工解析。例如下述代码中的Dismantle()函数,就等效于encode(‘latin1’):

print u'姹夊瓧缂栫爜'.encode('gbk').decode('utf8')

通过正确地编解码,可以完全消除乱码:

中文处理建议

Python2.x中默认编码为ASCII,而Python3中默认编码为Unicode。因此,如果可能应尽快迁移到Python3。否则,应遵循以下建议:
1) 源代码文件使用字符编码声明,且保存为所声明的编码格式。同一工程中的所有源代码文件也应使用和保存为相同的字符编码。若工程跨平台,应尽量统一为UTF-8编码。
2) 程序内部全部使用Unicode字符串,只在输出时转换为特定的编码。对于源码内的字符串常量,可直接添加Unicode前缀(“u”或”U”);对于从外部读取的字节序列,可按照”Decode early->Unicode everywhere->Encode late”的步骤处理。但按照”due”步骤手工处理文件时不太方便,可使用codecs.open()方法替代内置的open()。
此外,小段程序的编码问题可能并不明显,若能保证处理过程中使用相同编码,则无需转换为Unicode字符串。
3) 并非所有Python2.x内置函数或方法都支持Unicode字符串。这种情况下,可临时以正确的编码转换为字节序列,调用内置函数或方法完成操作后,立即以正确的编码转换为Unicode字符串。
4) 通过encode()和decode()编解码时,需要确定待转换字符串的编码。除显式约定外,可通过以下方法猜测编码格式:a.检测文件头BOM标记,但并非所有文件都有该标记;b.使用chardet.detect(str),但字符串较短时结果不准确;c.国际化产品最有可能使用UTF-8编码。
5) 避免在源码中显式地使用”mbcs”(别名”dbcs”)和”utf_16”(别名”U16”或”utf16”)的编码。
“mbcs”仅用于Windows系统,编码因当前系统ANSI码页而异。Linux系统的Python实现中并无”mbcs”编码,代码移植到Linux时会出现异常,如报告AttributeError: ‘module’ object has no attribute ‘mbcs_encode’。因此,应指定”gbk”等实际编码,而不要写为”mbcs”。
“utf_16”根据操作系统原生字节序指代”utf_16_be”或”utf_16_le”编码,也不利于移植。
6) 不要试图编写可同时处理Unicode字符串和字节序列的函数,这样很容易引入缺陷。
7) 测试数据中应包含非ASCII(包括EASCII)字符,以排除编码缺陷。

不写了,看了两天,自己的问题还是没解决,学习了!

[link 大部分参考学习的这个博客](http://www.cnblogs.com/tester-l/p/6056077.html)

阅读全文
0 0
原创粉丝点击