记录学习《流畅的python》的一些知识-----字符(2)

记录我学习《流畅的python》的过程

2021.1.18

1.处理文本文件
依赖默认编码来处理文本文件会遇到一些问题。

t = open('cafe.txt', 'w', encoding='utf_8').write('café')
print(t)
f = open('cafe.txt').read()
print(f)

运行结果:
在这里插入图片描述

问题是:写入文件时指定了utf-8编码,但是读取文件时没有这么做,使用的是系统默认的编码,所以会出现这种问题。

解决的办法:

fp = open('cafe.txt', 'w', encoding='utf_8')
print(fp)

print(fp.write('café'))
print(fp.close())

import os
print(os.stat('cafe.txt').st_size)

fp2 = open('cafe.txt')
print(fp2)
print(fp2.encoding)
print(fp2.read())

fp3 = open('cafe.txt', encoding='utf_8')#使用正确的编码打开文件
print(fp3)
print(fp3.read())

fp4 = open('cafe.txt', 'rb')#'rb'标志指明在二进制模式下读取文件
print(fp4)
print(fp4.read)

运行结果:
在这里插入图片描述
2.编码默认值
探索编码默认值

import sys,locale

expersions = """
             locale.getpreferredencoding()
             type(my_file)
             my_file.encoding
             sys.stdout.isatty()
             sys.stdout.encoding
             sys.stdin.isatty()
             sys.stdin.encoding
             sys.stderr.isatty()
             sys.stderr.encoding
             sys.getdefaultencoding()
             sys.getfilesystemencoding()
             """

my_file = open('dummy', 'w')

for expersion in expersions.split():
    value = eval(expersion)
    print(expersion.rjust(30), '->', repr(value))

运行结果:
在这里插入图片描述
关于编码默认值的最佳建议是:别依赖默认值。
2.正确比较,规范化Unicode字符串
用两种方式表示café,位数不一样,结果却一样。

s1 = 'café'
s2 = 'cafe\u0301'
print(s1, s2)

print(len(s1), len(s2))
print(s1 == s2)

运行结果:
在这里插入图片描述
s1和s2这两种序列成为标准等价物,应用程序把他们视作相同的字符,但是在python中码位不同,判定二者不同。
解决方案:使用unicodedata.normalize函数提供的Unicode规范化。

  • NFC,使用最少的码位构成等价的字符串

  • NFD,把组合字符分解成基字符和单独的组合字符

from unicodedata import normalize
s1 = 'café'  # 把“e”和重音符组合在一起
s2 = 'cafe\u0301' # 分解成“e”和重音符
print(len(s1), len(s2))

print(len(normalize('NFC', s1)), len(normalize('NFC', s2)))

print(len(normalize('NFD', s1)), len(normalize('NFD', s2)))

print(normalize('NFC', s1) == normalize('NFC', s2))
print(normalize('NFD', s1) == normalize('NFD', s2))

运行结果:
在这里插入图片描述

使用NFC,有些单字符会被规范化成另一个单字符。

from unicodedata import normalize,name
ohm = '\u2126'
print(name(ohm))

ohm_c = normalize('NFC', ohm)
print(name(ohm_c))

print(ohm == ohm_c)

print(normalize('NFC', ohm) == normalize('NFC', ohm_c))

运行结果:
在这里插入图片描述

  • NFKC,K表示兼容性
from unicodedata import normalize,name
half = '½'
print(normalize('NFKC', half))

four_squared = '4²'
print(normalize('NFKC', four_squared))

micro = 'μ'
micro_kc = normalize('NFKC', micro)
print(micro, micro_kc)

print(ord(micro), ord(micro_kc))
print(name(micro), name(micro_kc))

在这里插入图片描述
问题是输入法所输入的μ应该是不同,书上的结果两个μ不同。
微子符μ和小写希腊字母μ
3.大小写折叠
大小写折叠就是把所有文本变成小写,在做些其他转换。由str.casefold()实现
对于只包含latin1字符的字符串,它和lower一样,除了μ。

from unicodedata import name
micro = 'μ'
print(name(micro))

micro_cf = micro.casefold()
print(name(micro_cf))

print(micro, micro_cf)

eszett = 'β'
print(name(eszett))

eszett_cf = eszett.casefold()
print(name(eszett_cf))

运行结果:
在这里插入图片描述
这里的例子显示的都一样,可以选用一些其他的微字符来表示。
4.比较规范化Unicode字符串

rom unicodedata import normalize

def nfc_equal(str1, str2):
    return normalize('NFC', str1) == normalize('NFC', str2)

def fold_equal(str1, str2):
    return (normalize('NFC', str1).casefold() ==
            normalize('NFC', str2).casefold())

s1 = 'café'
s2 = 'cafe\u0301'
print(s1 == s2)

print(nfc_equal(s1, s2))
print(nfc_equal('a', 'A'))

s3 = 'Straße' # ß为德语的ss
s4 = 'strasse'
print('\n')
print(s3 == s4)
print(nfc_equal(s3, s4))
print(fold_equal(s3, s4))
print(fold_equal(s1, s2))
print(fold_equal('A', 'a'))

运行结果:
在这里插入图片描述
5.极端规范化
去掉字符串中的所有变音符号

import unicodedata
import string

def shave_marks(txt):
    """去掉全部变音符号"""
    norm_txt = unicodedata.normalize('NFD', txt) # 把所有字符分解成基字符和组合符号
    shaved = ''.join(c for c in norm_txt
                     if not unicodedata.combining(c)) # 过滤所有组合记号
    return unicodedata.normalize('NFC', shaved) # 重组

order = '"Herr Voß: · ½ cup of tker caffòǒèīèě"'
print(shave_marks(order))

在这里插入图片描述
深入规范化:

import unicodedata
import string

def shave_marks_latin(txt):
    """把拉丁基字符中的所有的变音符号删除"""
    norm_txt = unicodedata.normalize('NFD', txt) # 把所有字符分解成基字符和组合符号
    latin_base = False
    keepers = []
    for c in norm_txt:
        if unicodedata.combining(c) and latin_base:
            continue # 忽略拉丁基字符上的变音符号
        keepers.append(c)
        # 如果不是组合字符,那就是新的基字符
        if not unicodedata.combining(c):
            latin_base = c in string.ascii_letters
    shaved = ''.join(keepers)
    return unicodedata.normalize('NFC', shaved) # 重组

order = '"Herr Voß: · ½ cup of tker caffòǒèīèě"'
print(shave_marks_latin(order))

在这里插入图片描述
这里面没有变音的非希腊字母,可以自行示范。
6.Unicode文本排序
初始排序:

fruits = ['caju', 'atemoia', 'cajá', 'açai', 'acerola']
sorted_fruits = sorted(fruits)
print(sorted_fruits)

在这里插入图片描述

优化后:

import locale
print(locale.setlocale(locale.LC_COLLATE, 'pt_BR.UTF-8'))
fruits = ['caju', 'atemoia', 'cajá', 'açai', 'acerola']
sorted_fruits = sorted(fruits, key=locale.strxfrm)
print(sorted_fruits)

在这里插入图片描述

使用Unicode排序算法排序:

import pyuca
coll = pyuca.Collator()
fruits = ['caju', 'atemoia', 'cajá', 'açai', 'acerola']
sorted_fruits = sorted(fruits, key=coll.sort_key)
print(sorted_fruits)

在这里插入图片描述
7.Unicode数据库

import unicodedata
import re

re_digit = re.compile(r'\d')

sample = '1\xbc\xb2\u0969\u216b\u2466\u2480\u3285'

for char in sample:
    print('U+%04x' % ord(char),
          char.center(6),
          're_dig' if re_digit.match(char) else '-',
          'isdig' if char.isdigit() else '-',
          'isnum' if char.isnumeric() else '-',
          format(unicodedata.numeric(char), '5.2f'),
          unicodedata.name(char),
          sep='\t')

在这里插入图片描述
8.支持字符串和字节序列的双模式API
可以使用正则表达式搜索字符串和字节序列,但是在后一种情况中,ASCII范围外的字节不会当成数字和组成单词的字母。

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³.")

text_bytes = text_str.encode('utf-8')

print('Text', repr(text_str), sep='\n  ')
print('Numbers')
print('  str  :', re_numbers_str.findall(text_str))
print('  bytes:', re_numbers_bytes.findall(text_bytes))
print('Words')
print('  str  :', re_words_str.findall(text_str))
print('  bytes:', re_numbers_bytes.findall(text_bytes))

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值