Python實用技法第28篇:將Unicode文字統一表示為規範形式

Mark發表於2019-02-16

上一篇文章:Python實用技法第27篇:編寫多行模式的正規表示式
下一篇文章:Python實用技法第29篇:用正規表示式處理Unicode字元

1、需求?

我們正在同Unicode字串打交道,但需要確保所有的字串都擁有相同的底層表示。

2、解決方案?

在Unicode中,有些特定的字元可以被表示成多種合法的程式碼點序列。為了說明這個問題,請看下面示例:

str1=`u00f1`
str2=`nu0303`
str3=`u0303`

print(str1)
print(str2)
print(str3)

print(str1==str2)
print(len(str1))
print(len(str2))

執行結果:

ñ
ñ
̃
False
1
2

這裡的文字ñ是以兩種形式呈現:

  • 第一種使用的是字元ñ的【全組成】形式:U+00F
  • 第二種使用的是拉丁字母n緊跟著一個“~”,【組合】而成的字元:U+0303

對於一個比較字串的程式來說,同一個文字擁有多種不同的表示形式是個大問題。為了解決這個問題,應該先將文字同一表示為規範形式,這可以通過unicodedata模組來完成。

例項:

import unicodedata
str1=`u00f1`
str2=`nu0303`

t1=unicodedata.normalize(`NFC`,str1)
t2=unicodedata.normalize(`NFC`,str2)

print(t1)
print(t2)

print(t1==t2)

print(len(t1))
print(len(t2))

print(`*`*10)

t3=unicodedata.normalize(`NFD`,str1)
t4=unicodedata.normalize(`NFD`,str2)
print(t3)
print(t4)

print(t3==t4)

print(len(t3))
print(len(t4))

結果:

ñ
ñ
True
1
1
**********
ñ
ñ
True
2
2

normalize()的第一個引數指定了字串應該如何完成規範表示。

  • NFC表示字串應該是【全組成】的(即,如果可能的話使用單個程式碼點)。
  • NFD表示應該使用【組合】字元,每個字元應該是能完全分解的。

Python還支援NFKC和NFKD的規範表示形式,它們為處理特定型別的字元增加額額外的相容功能。

例項:

import unicodedata
str=`ufb01`

print(str)
print(len(str))
print(`*`*10)

t_nfd=unicodedata.normalize(`NFD`,str)
t_nfkd=unicodedata.normalize(`NFKD`,str)
t_nfc=unicodedata.normalize(`NFC`,str)
t_nfkc=unicodedata.normalize(`NFKC`,str)

print(t_nfd)
print(len(t_nfd))
print(`*`*10)

print(t_nfkd)
print(len(t_nfkd))
print(`*`*10)

print(t_nfc)
print(len(t_nfc))
print(`*`*10)

print(t_nfkc)
print(len(t_nfkc))

執行結果:

fi
1
**********
fi
1
**********
fi
2
**********
fi
1
**********
fi
2

3、分析?

對於任何需要確保以規範和一致性的方式進行處理Unicode文字的程式來說,規範化都是重要的一部分。尤其是在處理使用者輸入時接收到的字串時,此時你無法控制字串的編碼方式,那麼規範化文字的表示就顯得更為重要了。

在對文字進行過濾和淨化時,規範化同樣也佔據了重要的部分。例如,假設想從某些文字中去除所有的音符標記(可能是為了進行搜尋或匹配):

import unicodedata
str=`啦啦啦ufb01我是測試u00f1呱呱呱nu0303`

t1=unicodedata.normalize(`NFD`,str)
print(str)
print(t1)

#使用combining()函式判斷指定內容是否為一個組合型字元。
result=``.join(x for x in t1 if not unicodedata.combining(x))
print(result)

執行結果:

啦啦啦fi我是測試ñ呱呱呱ñ
啦啦啦fi我是測試ñ呱呱呱ñ
啦啦啦fi我是測試n呱呱呱n

很顯然,Unicode是一個龐大的主題,要獲得更多相關內容,可以參考:

http://www.unicode.org/faq/no…

https://nedbatchelder.com/tex…

上一篇文章:Python實用技法第27篇:編寫多行模式的正規表示式
下一篇文章:Python實用技法第29篇:用正規表示式處理Unicode字元

相關文章