Python3 中一串非英文字符的正确长度

Correct length of a string of non-English characters in Python3

我在一个文件中得到了一串希伯来字符(和其他一些阿拉伯字符。我都不认识)

阿拉伯语

当我从 Python3

中的文件加载此字符串时
fin = open("filename")
x = next(fin).strip()

x的长度好像是5

>>> len(x)
5

它的unicode utf-8编码是

>>> x.encode("utf-8")
b'\xd7\xa6\xd7\x95\xd6\xb9\xd7\xa8\xe2\x80\x8e'

但是在浏览器中,很明显这些希伯来字符的长度是3。

如何正确获取长度?为什么会这样?

我知道 Python 3 默认是 unicode 所以我没想到会有这样的问题。

您是否尝试过 io 库?

>>> import io
>>> with io.open('text.txt',  mode="r", encoding="utf-8") as f:
     x = f.read()
>>> print(len(x))

你也可以试试codecs:

>>> import codecs
>>> with codecs.open('text.txt', 'r', 'utf-8') as f:
     x = f.read()
>>> print(len(x))

原因是包含的文本包含控制字符 \u200e,它是用作 Left-to-right 标记的不可见字符(通常在混合多种语言时使用,以在 Left-to 之间划界-右和从右到左)。此外,它还包括元音 "character"(第二个字符上方的小点显示它的发音)。

例如,如果将 LTR 标记替换为空字符串,则长度为 4:

>> x = 'צוֹר'
>> x
'צוֹר\u200e' # note the control character escape sequence
>> print(len(x))
5

>> print(len(x.replace('\u200e', ''))
4

如果你只想要严格的字母字符和 space 个字符的长度,你可以对所有非 space 非单词字符执行类似 re.sub 的操作:

>> print(len(re.sub('[^\w\s]', '', x)))
3

Unicode 字符有不同的类别。在你的情况下:

>>> import unicodedata
>>> s = b'\xd7\xa6\xd7\x95\xd6\xb9\xd7\xa8\xe2\x80\x8e'.decode("utf-8")
>>> list(unicodedata.category(c) for c in s)
['Lo', 'Lo', 'Mn', 'Lo', 'Cf']
  • Lo:字母、其他(不是大写、小写等)。这些是 "real" 个字符
  • Mn:标记,非间距。这是与前一个字符组合的某种重音字符
  • Cf:控件,格式。这里它切换回从左到右的写入方向

打开utf-8编码的文件。

fin = open('filename','r',encoding='utf-8')

with open('filename','r',encoding='utf-8') as fin:
    for line1 in fin:
        print(len(line1.strip()))