设为首页 收藏本站
查看: 827|回复: 0

[经验分享] python与编码

[复制链接]

尚未签到

发表于 2015-11-30 08:57:54 | 显示全部楼层 |阅读模式
Python中的文字对象
  Python 3.x中处理文字的对象有str, bytes, bytearray。


  • bytes和bytearray可以使用除了用作格式化的方法(format, format_map)以及几个特殊的基于Unicode的方法(casefold, isdecimal, isidentifier, isnumeric, isprintable, encode)以外几乎所有str的方法。  

  •   bytes有一个类方法,可以通过序列来构建字符串,而这个方法不可以用在str上。
      

    >>> b = bytes.fromhex('E4 B8 AD')  
    >>> b
      
    b'\xe4\xb8\xad'
      
    >>> b.decode('utf-8')
      
    '中'
      
    >>> str(b)
      
    "b'\\xe4\\xb8\\xad'"
      

    Unicode和字符转换
      采用chr可以把一个Unicode的code point转换为字符,通过ord可以进行反向操作。
      

    >>> ord('A')  
    65
      
    >>> ord('中')
      
    20013
      
    >>> chr(65)
      
    'A'
      
    >>> chr(20013)
      
    '中'

len函数计算的是字符数,不是字节数
  

>>> len('中')  
1
  
>>> '中'.encode('utf-8')
  
b'\xe4\xb8\xad'
  
>>> len('中'.encode('utf-8'))    #计算的是bytes对象的长度,包含3个整数字符
  
3
  

Python与编码

Python内部处理编码的方式
  在Python接受我们的输入时,总是会先转为Unicode。而且这个过程越早越好。
  然后Python的处理总是对Unicode进行的,在这个过程中,一定不要进行编码转换的工作。
  在Python向我们返回结果时,总是会从Unicode转为我们需要的编码。而且这个过程越晚越好。

Python源码的编码方式
  Python默认使用utf-8编码。
  如果想使用一种不同的编码方式来保存Python代码,我们可以在每个文件的第一行或者第二行(如果第一行被hash-bang命令占用了)放置编码声明(encoding declaration)
  # ‐*‐ coding: windows‐1252 ‐*‐

Python中使用的编码
  

C:\Users\JL>chcp        #查找操作系统使用的编码  
Active code page: 936
  
>>> import sys, locale
  
>>> locale.getpreferredencoding()    #这个是最重要的
  
'cp936'
  
>>> my_file = open('cafe.txt','r')
  
>>> type(my_file)
  

  
>>> my_file.encoding    #文件对象默认使用locale.getpreferreddecoding()的值
  
'cp936'
  
>>> sys.stdout.isatty(), sys.stdin.isatty(), sys.stderr.isatty()    #output是否是控制台console
  
(True, True, True)
  
>>> sys.stdout.encoding, sys.stdin.encoding, sys.stderr.encoding    #sys的标准控制流如果被重定向,或者定向到文件,那么编码将使用环境变量PYTHONIOENCODING的值、控制台console的编码、或者locale.getpreferredencoding()的编码,优先级依次减弱。
  
('cp936', 'cp936', 'cp936')
  
>>> sys.getdefaultencoding()    #如果Python需要把二进制数据转为字符对象,那么在缺省情况下使用该值。
  
'utf-8'
  
>>> sys.getfilesystemencoding()    #Python用来编码或者解码文件名(不是文件内容)的时候,默认使用该编码。
  
'mbcs'
  

  以上是在Windows中的测试结果,如果在GNU/Linux或者OSX中,那么所有的结果都是UTF-8.
  关于mbcs和utf-8的区别,可以参考http://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows

文件读写的编码
  

>>> pen('cafe.txt','w',encoding='utf-8').write('café')  
4
  
>>> fp = open('cafe.txt','r')
  
>>> fp.read()
  
'caf茅'
  
>>> fp.encoding
  
'cp936'
  
>>> open('cafe.txt','r', encoding = 'cp936').read()
  
'caf茅'
  
>>> open('cafe.txt','r', encoding = 'latin1').read()
  
'café'
  
>>> fp = open('cafe.txt','r', encoding = 'utf-8')
  
>>> fp.encoding
  
'utf-8'
  

  从上面的例子可以看出,无论什么时候都不要使用默认的编码,因为在不同的机器上运行的时候会出现意想不到的问题。

Python如何处理来自Unicode的麻烦
  Python总是通过code point来比较字符串的大小,或者是否相等的。


  •   Unicode中重音符号有两种表示方法,用一个字节表示,或者用基字母加上重音符号表示,在Unicode中他们是相等的,但是在Python中由于通过code point来比较大小,所以就不相等了。
      

    >>> c1 = 'cafe\u0301'  
    >>> c2 = 'café'
      
    >>> c1 == c2
      
    False
      
    >>> len(c1), len(c2)
      
    (5, 4)
      

      解决方法是通过unicodedata库中的normalize函数,该函数的第一个参数可以接受"NFC",'NFD','NFKC','NFKD'四个参数中的一个。
      NFC(Normalization Form Canonical Composition):以标准等价方式来分解,然后以标准等价重组之。若是singleton的话,重组结果有可能和分解前不同。尽可能的缩短整个字符串的长度,所以会把'e\u0301'2个字节压缩到一个字节'é'。
      NFD(Normalization Form Canonical Decomposition):以标准等价方式来分解
      NFKD(Normalization Form Compatibility Decomposition):以相容等价方式来分解
      NFKC(Normalization Form Compatibility Composition):以相容等价方式来分解,然后以标准等价重组之。
      NFKC和NFKD可能会引起数据损失。

  

from unicodedata import normalize  
>>> c3 = normalize('NFC',c1)        #把c1往字符串长度缩短的方向操作
  
>>> len(c3)
  
4
  
>>> c3 == c2
  
True
  
>>> c4 = normalize('NFD',c2)
  
>>> len(c4)
  
5
  
>>> c4 == c1
  
True
  

  西方的键盘通常会键入尽可能短的字符串,也就是说和"NFC"的结果一致,但是通过"NFC"来操作一下再比较字符串是否相等比较安全。且W3C建议使用"NFC"的结果。


  •   同样的一个字符在Unicode中有两个不同的编码。
      该函数会把一个单一的Unicode字符转为另一个Unicode字符。
      

    >>> o1 = '\u2126'  
    >>> o2 = '\u03a9'
      
    >>> o1, o2
      
    ('Ω', 'Ω')
      
    >>> o1 == o2
      
    False
      
    >>> name(o1), name(o2)
      
    ('OHM SIGN', 'GREEK CAPITAL LETTER OMEGA')
      
    >>> o3 = normalize('NFC',o1)
      
    >>> name(o3)
      
    'GREEK CAPITAL LETTER OMEGA'
      
    >>> o3 == o2
      
    True
      

      又比如
      

    >>> u1 = '\u00b5'  
    >>> u2 = '\u03bc'
      
    >>> u1,u2
      
    ('µ', 'μ')
      
    >>> name(u1), name(u2)
      
    ('MICRO SIGN', 'GREEK SMALL LETTER MU')
      
    >>> u3 = normalize('NFKD',u1)
      
    >>> name(u3)
      
    'GREEK SMALL LETTER MU'
      

      再一个例子
      

    >>> h1 = '\u00bd'  
    >>> h2 = normalize('NFKC',h1)
      
    >>> h1, h2
      
    ('½', '1⁄2')
      
    >>> len(h1), len(h2)
      
    (1, 3)

  •   有时候我们希望使用不区分大小写的形式进行比较
      使用方法str.casefold(),该方法会把大写字母转换为小写进行比较,比如'A'会转为'a','MICRO SIGN'的'µ'会转换为'GREEK SMALL LETTER MU'的'µ'
      在绝大部分(98.9%)情况下str.casefold()和str.lower()的结果一致。

  •   文字排序
      由于不同的语言规则,如果单纯按照Python的比较code point的方式进行,那么会出现很多不是用户期望的结果。
      通常采用locale.strxfrm进行排序。
      

    >>> import locale  
    >>> locale.setlocale(locale.LC_COLLATE,'pt_BR.UTF-8')
      
    'pt_BR.UTF-8'
      
    >>> sort_result = sorted(intial, key = locale.strxfrm)
      

    编码解码错误
      如果是Python源码中出现了解码错误,那么会产生SyntaxError异常。
      其他情况下,如果发现编码解码错误,那么会产生UnicodeEncodeError, UnicodeDecodeError异常。

几个摘自fluent python中的有用方法
  

from unicodedata import normalize, combining  
def nfc_equal(s1, s2):
  '''return True if string s1 is eual to string s2 after normalization under "NFC" '''
  return normalize("NFC",s1) == normalize("NFC",s2)
  

  
def fold_equal(s1, s2):
  '''return True if string s1 is eual to string s2 after normalization under "NFC" and casefold()'''
  return normalize('NFC',s1).casefold() == normalize('NFC',s2).casefold()
  

  
def shave_marks(txt):
  '''Remove all diacritic marks
  basically it only need to change Latin text to pure ASCII, but this func will change Greek letters also
  below shave_latin_marks func is more precise'''
  

  normal_txt = normalize('NFD',txt)
  shaved = ''.join(c for c in normal_txt if not combining(c))
  return normalize('NFC',shaved)
  

  
def shave_latin_marks(txt):
  '''Remove all diacritic marks from Latin base characters'''
  normal_txt = normalize('NFD',txt)
  keeping = []
  latin_base=False
  for c in normal_txt:
  if combining(c) and latin_base:
  continue    #Ingore diacritic marks on Latin base char
  keeping.append(c)
  #If it's not combining char, it should be a new base char
  if not combining(c):
  latin_base = c in string.ascii_letters
  

编码探嗅Chardet
  这是Python的标准模块。
  参考资料:


  • http://blog.csdn.net/tcdddd/article/details/8191464

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145132-1-1.html 上篇帖子: 使用七牛云存储----大家自己的图床[python] 下篇帖子: Python——errno
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表