支持字符串和字节序列的双模式API

支持字符串和字节序列的双向API

标准库中的一些函数能接受字符串或字节序列作为参数,然后根据类型展现不同的行为。re和os模块中就有这样的函数

正则表达式中的字符串和字节序列

如果使用字节序列构建正则表达式,\d和\w等模式只能匹配ASCII字符;相比之下,如果是字符串模式,就能匹配ASCII之外的Unicode数字或字母

# 比较简单的字符串正则表达式和字节序列正则表达式的行为
import re

re_numbers_str = re.compile(r'\d+')  # 字符串类型正则表达式
re_words_str = re.compile(r'\w+')
re_numbers_bytes = re.compile(rb'\d+')  # 字节序列类型正则表达式
re_words_bytes = re.compile(rb'\w+')
text_str = ('Ramanujan saw \u0be7\u0bed\u0be8\u0bef' + 'as 1729 = 1³+ 12³ = 9³ + 10³.')  # 要搜索的Unicode文本,包括1729的泰米尔数字
text_bytes = text_str.encode('utf8')  # 编码为字节序列
print('Text', repr(text_str), sep='\n')
print('Numbers')
print('str  :', re_numbers_str.findall(text_str))  # 字符串模式r'\d+'只能匹配泰米尔数字和ASCII数字
print('bytes:', re_numbers_bytes.findall(text_bytes))  # 字节序列模式rb'\d+'只能匹配ASCII字节中的数字
print('Words')
print('str  :', re_words_str.findall(text_str))  # 字符串模式r'\w+'只能匹配字母、上标、泰米尔数字和ASCII数字
print('bytes:', re_words_bytes.findall(text_bytes))  # 字节序列模式rb'\w+'只能匹配ASCII字节中的字母和数字
Text
'Ramanujan saw ௧௭௨௯as 1729 = 1³+ 12³ = 9³ + 10³.'
Numbers
str  : ['௧௭௨௯', '1729', '1', '12', '9', '10']
bytes: [b'1729', b'1', b'12', b'9', b'10']
Words
str  : ['Ramanujan', 'saw', '௧௭௨௯as', '1729', '1³', '12³', '9³', '10³']
bytes: [b'Ramanujan', b'saw', b'as', b'1729', b'1', b'12', b'9', b'10']

os函数中的字符串和字节序列

GNU/Linux内核对Unicode的支持并不完善,有一些使用了字节序列的文件名,无法用任何合理的编码方案解码成字符串。在不同操作系统中使用各种客户端的文件服务器,在遇到这个问题时尤其容易出错。

为了规避这个问题,os模块中的所有函数、文件名或路径名参数既能使用字符串,也能使用字节序列。如果这样的函数使用字符串参数调用,该参数会使用sys.getfilesystemencoding()得到的编解码器自动编码,然后操作系统会使用相同的编解码器解码。

如果,必须处理那么无法使用上述方式自动处理的文件名,可以把字节序列参数传递给os模块中的函数,得到字节序列返回值。这一特性允许处理任何文件名或路径名

import os

os.listdir('.')
['.idea',
 '.ipynb_checkpoints',
 'Unicode文本排序.ipynb',
 '为了正确比较而规范Unicode字符串.ipynb',
 '了解编码问题.md',
 '处理文本文件.ipynb',
 '字符概要.ipynb',
 '字符问题.ipynb',
 '支持字符串和字节序列的双模式API.ipynb']
os.listdir(b'.')
[b'.idea',
 b'.ipynb_checkpoints',
 b'Unicode\xe6\x96\x87\xe6\x9c\xac\xe6\x8e\x92\xe5\xba\x8f.ipynb',
 b'\xe4\xb8\xba\xe4\xba\x86\xe6\xad\xa3\xe7\xa1\xae\xe6\xaf\x94\xe8\xbe\x83\xe8\x80\x8c\xe8\xa7\x84\xe8\x8c\x83Unicode\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2.ipynb',
 b'\xe4\xba\x86\xe8\xa7\xa3\xe7\xbc\x96\xe7\xa0\x81\xe9\x97\xae\xe9\xa2\x98.md',
 b'\xe5\xa4\x84\xe7\x90\x86\xe6\x96\x87\xe6\x9c\xac\xe6\x96\x87\xe4\xbb\xb6.ipynb',
 b'\xe5\xad\x97\xe7\xac\xa6\xe6\xa6\x82\xe8\xa6\x81.ipynb',
 b'\xe5\xad\x97\xe7\xac\xa6\xe9\x97\xae\xe9\xa2\x98.ipynb',
 b'\xe6\x94\xaf\xe6\x8c\x81\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2\xe5\x92\x8c\xe5\xad\x97\xe8\x8a\x82\xe5\xba\x8f\xe5\x88\x97\xe7\x9a\x84\xe5\x8f\x8c\xe6\xa8\xa1\xe5\xbc\x8fAPI.ipynb']
  • fsencode(filename)
    如果filename是str类型(此外还可能是bytes类型),使用sys.getfilesystemencoding()返回的编解码器把filename编码成字节序列;否则,返回未经修改的filename字节序列
  • fsdecode(filename)
    如果filename是bytes类型(此外还可能是str类型),使用sys.getfilesystemencoding()返回的编解码器把filename编码成字符串;否则,返回未经修改的filename字符串

在Unix衍生平台中,这些函数使用surrogateescape错误处理方式以避免遇到意外字节序列时卡住。Windows使用的错误处理方式是strict

syrrigateescape错误处理方式会把每个无法解码的字节替换成Unicode中U+DC00到U+DCFF之间的码位(Unicode标准把这些码位称为‘Low Surrogate Area’),这些码位是保留的,没有分配字符,供程序内部使用。编码时,这些码位会被转换成被替换的字节值

# 使用surrogateescape错误处理方式
os.listdir('.')
['.idea',
 '.ipynb_checkpoints',
 'Unicode文本排序.ipynb',
 '为了正确比较而规范Unicode字符串.ipynb',
 '了解编码问题.md',
 '处理文本文件.ipynb',
 '字符概要.ipynb',
 '字符问题.ipynb',
 '支持字符串和字节序列的双模式API.ipynb']
os.listdir(b'.')
[b'.idea',
 b'.ipynb_checkpoints',
 b'Unicode\xe6\x96\x87\xe6\x9c\xac\xe6\x8e\x92\xe5\xba\x8f.ipynb',
 b'\xe4\xb8\xba\xe4\xba\x86\xe6\xad\xa3\xe7\xa1\xae\xe6\xaf\x94\xe8\xbe\x83\xe8\x80\x8c\xe8\xa7\x84\xe8\x8c\x83Unicode\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2.ipynb',
 b'\xe4\xba\x86\xe8\xa7\xa3\xe7\xbc\x96\xe7\xa0\x81\xe9\x97\xae\xe9\xa2\x98.md',
 b'\xe5\xa4\x84\xe7\x90\x86\xe6\x96\x87\xe6\x9c\xac\xe6\x96\x87\xe4\xbb\xb6.ipynb',
 b'\xe5\xad\x97\xe7\xac\xa6\xe6\xa6\x82\xe8\xa6\x81.ipynb',
 b'\xe5\xad\x97\xe7\xac\xa6\xe9\x97\xae\xe9\xa2\x98.ipynb',
 b'\xe6\x94\xaf\xe6\x8c\x81\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2\xe5\x92\x8c\xe5\xad\x97\xe8\x8a\x82\xe5\xba\x8f\xe5\x88\x97\xe7\x9a\x84\xe5\x8f\x8c\xe6\xa8\xa1\xe5\xbc\x8fAPI.ipynb']
上一篇:VSCode解决运行ipynb文件使用卡顿问题


下一篇:matpb画图_折线图.ipynb