UTF−8 には濁点の扱いが2種類ある、というのは有名な話。例えば、「が」。
「か」 In [3]: u"か".encode("utf-8") Out[3]: '\xe3\x81\x8b' 「が」 NKC In [8]: unicodedata.normalize("NFC", u"が").encode("utf-8") Out[8]: '\xe3\x81\x8c' NFD In [9]: unicodedata.normalize("NFD", u"が").encode("utf-8") Out[9]: '\xe3\x81\x8b\xe3\x82\x99' NFKC In [11]: unicodedata.normalize("NFKC", u"が").encode("utf-8") Out[11]: '\xe3\x81\x8c' NFKD In [10]: unicodedata.normalize("NFKD", u"が").encode("utf-8") Out[10]: '\xe3\x81\x8b\xe3\x82\x99'
NKCはComposition、合成。だから「が」は 「か」から1ビットずれる 「x8b → x8c」
NKDはDecomposition、分解。だから「が」は「か+゛」なので「'\xe3\x81\x8b' + '\xe3\x82\x99'」
さて、では、「ガ」はどうなるだろうか?
In [46]: u"カ".encode("utf-8") Out[46]: '\xe3\x82\xab' In [44]: [unicodedata.normalize(_type, u"ガ").encode("utf-8") for _type in ("NFC", "NFD", "NFKC", "NFKD")] Out[44]: ['\xe3\x82\xac', '\xe3\x82\xab\xe3\x82\x99', '\xe3\x82\xac', '\xe3\x82\xab\xe3\x82\x99']
うん、法則は変わらない。
では、半角カナはどうだろうか?半角カナの濁点は「分解型」だよね。
In [89]: u"カ".encode("utf-8") Out[89]: '\xef\xbd\xb6' In [88]: [unicodedata.normalize(_type, u"ガ").encode("utf-8") for _type in ("NFC", "NFD", "NFKC", "NFKD")] Out[88]: ['\xef\xbd\xb6\xef\xbe\x9e', '\xef\xbd\xb6\xef\xbe\x9e', '\xe3\x82\xac', '\xe3\x82\xab\xe3\x82\x99']
半角カナは、NKFCのみ、合成型になる。そして、NFCとNFDは同じ。
ということで、Windows とか考えると無難なのはNFCなのかな?