Python 3、统计泰文字符位置
In Python 3, count Thai character positions
FIRST,我用过Python3grapheme library to solve my problem. (For a bit more about grapheme, see this article)。但令我惊讶的是 Python 3 没有专门的库就无法做到这一点...
我求助于 grapheme 因为经过多次网络搜索和阅读 Whosebug 问题后,我无法得到 Python 3 到 return 正确的数字泰语字符序列中的 个字符位置。
例如,这是一个 UTF-8 泰文字符串:
thai_str = 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว'
我使用术语字符位置 来标识 line/string 泰语字符中的单个位置。这是因为字符位置可能由泰语辅音加上(在某些情况下)辅音上方或下方的元音或声调标记组成。辅音加上元音或声调标记 above/below 在 Unicode 字符串中占据单个 字符位置 。 (一些泰语辅音也可能在其左侧、右侧或两者都有元音。这些元音占据它们自己的字符位置。)
例如,在从示例字符串生成的以下序列中,第 2 项和第 7 项是元音,第 10 项是声调标记。每个使用 UTF-8 字符串中的单独字节,但不占用自己的字符位置。第 3 项和第 8 项是位于辅音左侧的元音,因此占据字符位置。
01: ส
02: ี
03: โ
04: ช
05: ค
06: ด
07: ี
08: เ
09: ป
10: ็
...
45: ว
尝试确定示例字符串中的字符位置时,len(thai_str)
returns 45
。这是不正确的。我能够获得正确数量的字符位置的唯一方法是使用 grapheme.length(thai_str)
来获得 35
.
我还使用 encode 获得以下内容:
b'\xe0\xb8\xaa\xe0\xb8\xb5\xe0\xb9\x82\xe0\xb8\x8a\xe0\xb8\x84\xe0\xb8\x94...
(计算似乎在每个泰语字符之前的 xe0
的实例并不像正确的方法...)
SO - 计算我的示例字符串中字符位置的唯一方法是使用 Python 3 库,例如 grapheme?
这不是唯一的方法,如果你想自己实现一个字素计数器,但它很复杂,你必须参考 https://unicode.org 规范才能正确使用。
thai_str
不是UTF-8字符串,而是包含Unicode码位的Unicode字符串。代码点有不同的categories。计算字符位置所需的示例文本使用的两个类别是:
Lo
Other_Letter,其他字母,包括音节和表意文字;
Mn
Nonspacing_Mark,一个非间距组合标记(零提前宽度)。
如果跳过 Nonspacing_Mark (Mn
) 类别的代码点,您可以大致看到字素库在做什么:
import unicodedata as ud
thai_str = 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว'
for cp in thai_str:
print(f'{cp}\t{ud.category(cp)}\t{ud.name(cp)}')
print(sum(1 for cp in thai_str if ud.category(cp)[0] != 'M'))
输出:
ส Lo THAI CHARACTER SO SUA
ี Mn THAI CHARACTER SARA II
โ Lo THAI CHARACTER SARA O
ช Lo THAI CHARACTER CHO CHANG
ค Lo THAI CHARACTER KHO KHWAI
ด Lo THAI CHARACTER DO DEK
ี Mn THAI CHARACTER SARA II
เ Lo THAI CHARACTER SARA E
ป Lo THAI CHARACTER PO PLA
็ Mn THAI CHARACTER MAITAIKHU
...
ว Lo THAI CHARACTER WO WAEN
35
更多解决方案,但也通过 扩展字素簇 (“用户感知的字符”),如 UAX #29 中指定:
使用 pyuegc 库
from pyuegc import EGC # pip install pyuegc
egc = EGC('สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว')
print(len(egc))
# 35
使用 regex 库
import regex # pip install regex
egc = regex.findall('\X', 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว')
print(len(egc))
# 35
FIRST,我用过Python3grapheme library to solve my problem. (For a bit more about grapheme, see this article)。但令我惊讶的是 Python 3 没有专门的库就无法做到这一点...
我求助于 grapheme 因为经过多次网络搜索和阅读 Whosebug 问题后,我无法得到 Python 3 到 return 正确的数字泰语字符序列中的 个字符位置。
例如,这是一个 UTF-8 泰文字符串:
thai_str = 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว'
我使用术语字符位置 来标识 line/string 泰语字符中的单个位置。这是因为字符位置可能由泰语辅音加上(在某些情况下)辅音上方或下方的元音或声调标记组成。辅音加上元音或声调标记 above/below 在 Unicode 字符串中占据单个 字符位置 。 (一些泰语辅音也可能在其左侧、右侧或两者都有元音。这些元音占据它们自己的字符位置。)
例如,在从示例字符串生成的以下序列中,第 2 项和第 7 项是元音,第 10 项是声调标记。每个使用 UTF-8 字符串中的单独字节,但不占用自己的字符位置。第 3 项和第 8 项是位于辅音左侧的元音,因此占据字符位置。
01: ส
02: ี
03: โ
04: ช
05: ค
06: ด
07: ี
08: เ
09: ป
10: ็
...
45: ว
尝试确定示例字符串中的字符位置时,len(thai_str)
returns 45
。这是不正确的。我能够获得正确数量的字符位置的唯一方法是使用 grapheme.length(thai_str)
来获得 35
.
我还使用 encode 获得以下内容:
b'\xe0\xb8\xaa\xe0\xb8\xb5\xe0\xb9\x82\xe0\xb8\x8a\xe0\xb8\x84\xe0\xb8\x94...
(计算似乎在每个泰语字符之前的 xe0
的实例并不像正确的方法...)
SO - 计算我的示例字符串中字符位置的唯一方法是使用 Python 3 库,例如 grapheme?
这不是唯一的方法,如果你想自己实现一个字素计数器,但它很复杂,你必须参考 https://unicode.org 规范才能正确使用。
thai_str
不是UTF-8字符串,而是包含Unicode码位的Unicode字符串。代码点有不同的categories。计算字符位置所需的示例文本使用的两个类别是:
Lo
Other_Letter,其他字母,包括音节和表意文字;Mn
Nonspacing_Mark,一个非间距组合标记(零提前宽度)。
如果跳过 Nonspacing_Mark (Mn
) 类别的代码点,您可以大致看到字素库在做什么:
import unicodedata as ud
thai_str = 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว'
for cp in thai_str:
print(f'{cp}\t{ud.category(cp)}\t{ud.name(cp)}')
print(sum(1 for cp in thai_str if ud.category(cp)[0] != 'M'))
输出:
ส Lo THAI CHARACTER SO SUA
ี Mn THAI CHARACTER SARA II
โ Lo THAI CHARACTER SARA O
ช Lo THAI CHARACTER CHO CHANG
ค Lo THAI CHARACTER KHO KHWAI
ด Lo THAI CHARACTER DO DEK
ี Mn THAI CHARACTER SARA II
เ Lo THAI CHARACTER SARA E
ป Lo THAI CHARACTER PO PLA
็ Mn THAI CHARACTER MAITAIKHU
...
ว Lo THAI CHARACTER WO WAEN
35
更多解决方案,但也通过 扩展字素簇 (“用户感知的字符”),如 UAX #29 中指定:
使用 pyuegc 库
from pyuegc import EGC # pip install pyuegc
egc = EGC('สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว')
print(len(egc))
# 35
使用 regex 库
import regex # pip install regex
egc = regex.findall('\X', 'สีโชคดีเป็นสีชมพู สีโชคร้ายเป็นสีเหลืองและขาว')
print(len(egc))
# 35