按字符拆分泰语文本

Splitting Thai text by characters

不以字为界,那是可以解决的。

示例:

#!/usr/bin/env python3  
text = 'เมื่อแรกเริ่ม'  
for char in text:  
    print(char)  

这会产生:






这显然不是想要的输出。有什么想法吗?

文本的可移植表示是:

text = u'\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e41\u0e23\u0e01\u0e40\u0e23\u0e34\u0e48\u0e21'

我无法完全重现,但这里是你脚本的一个轻微修改版本,在 Windows7 64 系统上的 IDLE 3.4 上输出:

>>> for char in text:
    print(char, hex(ord(char)), unicodedata.name(char),'-',
          unicodedata.category(char), '-', unicodedata.combining(char), '-',
          unicodedata.east_asian_width(char))


เ 0xe40 THAI CHARACTER SARA E - Lo - 0 - N
ม 0xe21 THAI CHARACTER MO MA - Lo - 0 - N
ื 0xe37 THAI CHARACTER SARA UEE - Mn - 0 - N
่ 0xe48 THAI CHARACTER MAI EK - Mn - 107 - N
อ 0xe2d THAI CHARACTER O ANG - Lo - 0 - N
แ 0xe41 THAI CHARACTER SARA AE - Lo - 0 - N
ร 0xe23 THAI CHARACTER RO RUA - Lo - 0 - N
ก 0xe01 THAI CHARACTER KO KAI - Lo - 0 - N
เ 0xe40 THAI CHARACTER SARA E - Lo - 0 - N
ร 0xe23 THAI CHARACTER RO RUA - Lo - 0 - N
ิ 0xe34 THAI CHARACTER SARA I - Mn - 0 - N
่ 0xe48 THAI CHARACTER MAI EK - Mn - 107 - N
ม 0xe21 THAI CHARACTER MO MA - Lo - 0 - N
>>>

我真的不知道那些字符是什么 - 我的泰语 非常 很差:-) - 但它表明:

  • 文本被确认为泰文 ...
  • 输出与 len(text) (13)
  • 一致
  • 字符组合时类别和组合不同

如果是预期的输出,证明你的问题不在Python,更多的是在你显示的console。您应该尝试将输出重定向到一个文件,然后在支持泰文字符的 unicode 编辑器中打开该文件。

如果预期输出只有 9 个字符,即如果您不想分解组合字符,并且没有其他应考虑的组合规则,您可以使用类似 :

def Thaidump(t):
    old = None
    for i in t:
        if unicodedata.category(i) == 'Mn':
            if old is not None:
                old = old + i
        else:
            if old is not None:
                print(old)
            old = i
    print(old)

这样 :

>>> Thaidump(text)
เ
มื่
อ
แ
ร
ก
เ
ริ่
ม
>>> 

tl;dr:使用\X正则表达式提取用户感知的字符:

>>> import regex # $ pip install regex
>>> regex.findall(u'\X', u'เมื่อแรกเริ่ม')
['เ', 'มื่', 'อ', 'แ', 'ร', 'ก', 'เ', 'ริ่', 'ม']

虽然我不懂泰语,但我懂一点法语。

考虑字母 è。让 ss2 等于 è 在 Python shell:

>>> s
'è'
>>> s2
'è'

同一个字母?在视觉上对讲法语的人来说,oui。对于计算机,否:

>>> s==s2
False

您可以使用 è 的实际代码点或通过使用字母 e 并添加添加该重音字符的组合代码点来创建相同的字母。他们有不同的编码:

>>> s.encode('utf-8')
b'\xc3\xa8'
>>> s2.encode('utf-8')
b'e\xcc\x80'

和不同的长度:

>>> len(s)
1
>>> len(s2)
2

但从视觉上看,两种编码都会导致 'letter' è。这称为 grapheme,或最终用户认为的一个字符。

您可以演示您所看到的相同循环行为:

>>> [c for c in s]
['è']
>>> [c for c in s2]
['e', '̀']

您的字符串中有多个组合字符。因此,您眼中的 9 个字素字符泰语字符串变成了 Python.

的 13 个字符字符串

法语中的解决方案是根据 Unicode 规范化字符串 equivalence:

>>> from unicodedata import normalize
>>> normalize('NFC', s2) == s
True

虽然这对许多非拉丁语言不起作用。一种处理 unicode 字符串的简单方法,这些字符串可能是由多个代码点组成 single grapheme is with a regex engine that correctly deals with this by supporting \X. Unfortunately Python's included re module doesn't yet.

建议的替换 regex 确实支持 \X,但:

>>> import regex
>>> text = 'เมื่อแรกเริ่ม'
>>> regex.findall(r'\X', text)
['เ', 'มื่', 'อ', 'แ', 'ร', 'ก', 'เ', 'ริ่', 'ม']
>>> len(_)
9

为了澄清之前的答案,您遇到的问题是缺少的字符是 "combining characters" - 必须与其他字符组合才能正确显示的元音和变音符号。没有单独显示这些字符的标准方法,但最常见的约定是使用虚线圆圈作为空辅音,如 Serge Ballesta 的答案所示。

那么问题是,对于您的应用程序,每个元音和变音符号都被视为一个单独的字符,还是您希望用 "print cell" 分隔,如 Serge 的回答所示?

顺便说一句,在正常使用中,除了在输入较长的单词的过程中,不应在没有后续辅音的情况下显示前导元音 SARA E 和 SARA AE。

有关详细信息,请参阅泰国 API 联盟 (TAPIC) 发布的 WTT 2.0 标准,其中定义了如何组合、显示字符以及如何处理错误。