Python正则表达式中的\w不能匹配组合变音符号吗?

11

我有一个带有组合变音符的UTF8字符串,我想用\w正则表达式序列匹配它。 它可以匹配具有重音的字符,但不能匹配带有组合变音符的拉丁字符。

>>> re.match("a\w\w\wz", u"aoooz", re.UNICODE)
<_sre.SRE_Match object at 0xb7788f38>
>>> print u"ao\u00F3oz"
aoóoz
>>> re.match("a\w\w\wz", u"ao\u00F3oz", re.UNICODE)
<_sre.SRE_Match object at 0xb7788f38>
>>> re.match("a\w\w\wz", u"aoo\u0301oz", re.UNICODE)
>>> print u"aoo\u0301oz"
aóooz

(看起来SO的markdown处理器在上面的组合变音符上有些问题,但是最后一行有一个 ́)

有没有办法用\w匹配组合变音符?我不想规范化文本,因为这个文本是从文件名中获取的,而且我不想进行整个“文件名Unicode规范化”操作。这是Python 2.5。

2个回答

7
我刚刚注意到 PyPI 上有一个新的 "regex" 包。(如果我理解正确,它是一个新包的测试版本,将在某一天取代 stdlib 的 re 包)。
它似乎有更多与 Unicode 相关的可能性。例如,它支持 \X,用于匹配单个字形(无论它是否使用组合)。它还支持匹配 Unicode 属性、块和脚本,因此您可以使用 \p{M} 来引用组合标记。前面提到的 \X 等效于 \P{M}\p{M}*(不是组合标记的字符,后跟零个或多个组合标记)。
请注意,这使得 \X 或多或少成为 . 的 Unicode 等价物,而不是 \w 的等价物,因此在您的情况下,\w\p{M}* 是您需要的。

目前它是非标准库包,我不知道它的准备情况(也没有二进制分发),但你可以试试,因为它似乎是回答你问题最简单/最“正确”的方法。(否则,我认为你只能明确地使用字符范围,如我对先前答案的评论所述)。

另请参见此页面,其中包含有关Unicode正则表达式的信息,这可能对您有用(并且可以作为regex软件包中实现的某些内容的文档)。


2
您可以使用unicodedata.normalize将组合变音符号组合成一个Unicode字符。
>>> import re
>>> from unicodedata import normalize
>>> re.match(u"a\w\w\wz", normalize("NFC", u"aoo\u0301oz"), re.UNICODE)
<_sre.SRE_Match object at 0x00BDCC60>

我知道你说过你不想规范化,但是我认为这个解决方案不会有问题,因为你只是将字符串规范化以进行匹配,并不需要改变文件名本身或其他什么。

2
是的,这可以告诉我是否有匹配项,但在进行匹配后,我会提取匹配组,然后对它们进行处理。如果我使用您的方法,那么之后得到的字节将不是文件名中所包含的相同字节。 - Amandasaurus
我明白了。你知道这些字符串在使用组合变音符时是否一致(始终组合,或者至少在单个字符串内始终组合或始终不组合)吗?如果是这样,您可以根据需要将结果规范化为NFC或NFD。否则,我认为您将不得不使用检测原始字符串中组合变音符位置的技巧,并尝试使用该信息仅分解所需字符(这当然比仅分解全部或不分解要更费力)。 - Steven
或者只需更改表达式并使用您感兴趣的组合变音符号范围,然后使用类似于\w [\ u0300- \ u036F]?而不是仅使用\w。 - Steven
1
不,输入在使用组合变音符号的方式上并不一致。有些使用组合字符,有些使用组合变音符号。 - Amandasaurus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接