python规范化字符串_Python进阶14_Unicode字符的规范化

Unicode字符的规范化

Unicode 三明治

关于处理文本文件这里有一个很有意思和形象的比喻:“Unicode 三明治”。可以想象成三部曲吧: - 第一步:要尽早把输入的字节序列解码输入的字节序列 - 然后:只处理文本 - 最后:要尽量晚地把字符串编码成字节序列 具体如下图:

python3中的操作函数: - 内置的open函数在读取文件的时候做解码 - read 和 write中的方法都市处理字符串

但是这里有一个默认编码问题:

如下面的实例所示,不同的平台使用的默认编码格式不一样,到时无法正确读取文件. 需要在多台设备中或多种场合下运行的代码,一定不能依赖默认编码。打开文件时始终应该明确传入 encoding= 参数

#  一个平台上的编码问题

# 写入的时候指定为utf_8

fo = open('cafe.txt','w',encoding='utf_8').write('café')

print(fo)

# 读取的时候使用默认的编码读取,window用的是cp936的格式

strfile = open('cafe.txt').read()

print(strfile)

4

caf茅

# 关于上例中的详解

# 返回一个 TextIOWrapper 对象

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

print(fp)

# 写入

fp.write('café')

fp.close()

# os.stat 报告文件中有 5 个字节

import os

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

# windows 默认的编码格式是encoding='cp936'

fp2 = open('cafe.txt')

print(fp2)

# 读取的是一个中文字符

print(fp2.read())

fp2.close()

# 这里指定的编码格式

fp3 = open('cafe.txt',encoding='utf_8')

print(fp3)

print(fp3.read())

fp3.close()

# 使用二进制格式读取

fp4 = open('cafe.txt','rb')

# 返回的是 BufferedReader 对象

print(fp4)

print(fp4.read())

5

caf茅

café

b'caf\xc3\xa9'

规范化Unicode字符串的函数

规范化Unicode字符串是为了正确的比较字符串而出现的。例如下面的例子: - café 与 cafe\u0301 - 分别的码位长度是4和5,但是结果是完成一样 - Python 看到的是不同的码位序列,因此判定二者不相等 - 应用程序应该把它们视作相同的字符

这里就需要:使用unicodedata.normalize进行规范化. 函数的第一个参数是的设置有四个选择: - NFC(Normalization Form C)使用最少的码位构成等价的字符串 - NFD 把组合字符分解成基字符和单独的组合字符 - NFKC 较严格的规范化形式,对“兼容字符”有影响 - NFKD 较严格的规范化形式,对“兼容字符”有影响

保存文本之前,最好使用 normalize('NFC', user_text) 清洗字符串.推荐使用NFC进行比较.

s1 = 'café'

s2 = 'cafe\u0301'

print("s1:",s1,"\ns2:", s2)

print("s1 len:",len(s1),"\ns2 len:", len(s2))

s1: café

s2: café

s1 len: 4

s2 len: 5

#normalize NFC 与NFD

from unicodedata import normalize

s1 = 'café'

s2 = 'cafe\u0301'

print("s1 len:",len(s1),"\ns2 len:", len(s2))

print("s1 NFC len:",len(normalize('NFC',s1)),

"\ns2 NFC len:", len(normalize('NFC',s2)))

print("s1 NFD len:",len(normalize('NFD',s1)),

"\ns2 NFD len:", len(normalize('NFD',s2)))

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

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

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

s1 len: 4

s2 len: 5

s1 NFC len: 4

s2 NFC len: 4

s1 NFD len: 5

s2 NFD len: 5

True

True

False

Unicode 大小写折叠

大小写折叠其实就是把所有文本变成小写,再做些其他转换。 - str.casefold()

只包含 latin1 字符的字符串 s,s.casefold() 得到的结果与 s.lower() 一样.str.casefold() 和 str.lower() 得到不同结果的有 116 个码位.

#Unicode 大小写折叠

from unicodedata import normalize, name

micro = 'µ'

print(name(micro))

micro_cf = micro.casefold()

print(name(micro_cf))

print(micro,micro_cf)

MICRO SIGN

GREEK SMALL LETTER MU

µ μ

Unicode 文本匹配函数

多语言文本处理时需要使用如下函数: - nfc_equal - fold_equal

from 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(fold_equal('a','A'))

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

False

True

True

False

极端“规范化”:去掉变音符号

在什么时候需要去掉变音符号: - 搜索涉及很多技术 - 去掉变音符号还能让 URL 更易于阅读

如何实现去掉变音符号:如下代码

#去掉全部组合记号的函数

import unicodedata

import string

def shave_marks(txt):

#把所有字符分解成基字符和组合记号

norm_txt = unicodedata.normalize('NFD',txt)

unicodedata.combining('a')

#过滤掉所有组合记号

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è latte • bowl of açaí.”'

print(shave_marks(order))

“Herr Voß: • ½ cup of Œtker™ caffe latte • bowl of acai.”

# 删除拉丁字母中组合记号的函数

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è latte • bowl of açaí.”'

print(shave_marks_latin(order))

“Herr Voß: • ½ cup of Œtker™ caffe latte • bowl of acai.”

关于Unicode字符规范化小结: - NFC 和 NFD 可以放心使用,而且能合理比较 Unicode 字符串 - 对大多数应用来说,NFC 是最好的规范化形式 - 不区分大小写的比较应该使用 str.casefold() - 文本匹配实用函数:要利用normalize,casefold - 去掉变音符号:需要注意不能把它们变成 ASCII 字符

请大家关注公众号:瓦力人工智能

分享关于人工智能,机器学习,深度学习以及计算机视觉的好文章,同时自己对于这个领域学习心得笔记。想要一起深入学习人工智能的小伙伴一起结伴学习吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值