在Mac上使用str.title()和编码

时间:2018-12-19 22:05:13

标签: python python-3.x macos encoding

假设我有3个文件夹,分别是“GrégoryMM”,“LoïcRR”和“DanièleRR”(空格和带重音的字母)。

然后,我使用以下代码获取所有名称,并且仅将首字母大写:

import glob
names = [ x.title() for x in glob.glob('*') ]

如果文件夹是使用mkdir从终端创建的,则可以得到预期的结果:

>>> names
['Loïc Rr', 'Danièle Rr', 'Grégory Mm']

如果文件夹是通过Finder创建的,我得到:

>>> names
['LoïC Rr', 'DanièLe Rr', 'GréGory Mm']

每个重音字母后的首字母大写。这是已知行为吗?我该如何避免呢?

Python版本3.7.0
系统:macOS Mojave 10.14.1
并且sys.getfilesystemencoding()返回'utf-8'

2 个答案:

答案 0 :(得分:1)

这很可能是重音字母使用组合重音字符还是单个重音代码点的问题。我不知道您的系统上实际上拥有什么文件名,但是将这些文件名以NFC格式(带有单个重音代码点)放置:

>>> x = 'Loïc Rr'
>>> unicodedata.normalize('NFC', x).title()
'Loïc Rr'

在使用重音符号时,我们没有大写字母,而在NFD形式(结合重音符号)中:

>>> unicodedata.normalize('NFD', x).title()
'Loi\u0308C Rr'

我们得到了资本。

似乎title()认为组合字符标记了单词边界。 NFC规范化可以有所帮助,但对于不存在专用代码点的怪异的重音组合则无济于事。为了获得更强大的处理能力,您可能想要寻找比Python内置字符串方法更强大的Unicode处理库。

答案 1 :(得分:1)

我们实际上有两个不同的字符串:

In [1]: 'Loïc Rr'.encode()
Out[1]: b'Lo\xc3\xafc Rr'

In [2]: 'Loïc Rr'.encode()
Out[2]: b'Loi\xcc\x88c Rr'

\xc3\xafï,而\xcc\x88̈

\xcc\x88被识别为标点符号,因此这就是title()用大写字母大写的原因。

您可以使用unicodedata.normalize()来规范化您的字符串:

In [1]: import unicodedata

In [2]: 'Loïc Rr' == 'Loïc Rr'
Out[2]: False

In [3]: unicodedata.normalize('NFC','Loïc Rr') == unicodedata.normalize('NFC','Loïc Rr')
Out[3]: True

In [4]: unicodedata.normalize('NFD','Loïc Rr') == unicodedata.normalize('NFD','Loïc Rr')
Out[4]: True

In [5]: unicodedata.normalize('NFD','Loïc Rr').title() == unicodedata.normalize('NFD','Loïc Rr').title()
Out[5]: True

In [6]: unicodedata.normalize('NFD','Loïc Rr').title() == unicodedata.normalize('NFD','Loïc Rr').title()
Out[6]: True