在Python中匹配Unicode单词边界

13
为了匹配Python中Unicode单词边界[如Annex #29定义],我一直在使用regex包和标志regex.WORD | regex.V1(由于模式为Unicode字符串,regex.UNICODE应该是默认的),用以下方式:
>>> s="here are some words"
>>> regex.findall(r'\w(?:\B\S)*', s, flags = regex.V1 | regex.WORD)
['here', 'are', 'some', 'words']
在这些相对简单的情况下它运行良好。然而,我想知道如果输入字符串包含某些标点符号时的预期行为是什么。在我的理解中,WB7 表明,例如 x'z 中的撇号不符合单词边界,这似乎的确是情况:
>>> regex.findall(r'\w(?:\B\S)*', "x'z", flags = regex.V1 | regex.WORD)
["x'z"]

然而,如果有元音字母,情况就会改变:

>>> regex.findall(r'\w(?:\B\S)*', "l'avion", flags = regex.V1 | regex.WORD)
["l'", 'avion']

这表明正则表达式模块实现了标准中在Notes部分提到的规则WB5a。然而,该规则还指出行为应与\u2019(右单引号)相同,但我无法复现:

>>> regex.findall(r'\w(?:\B\S)*', "l\u2019avion", flags = regex.V1 | regex.WORD)
['l’avion']
此外,即使使用“正常”的撇号,连字(或y)似乎也表现为“非元音”:
>>> regex.findall(r'\w(?:\B\S)*', "l'œil", flags = regex.V1 | regex.WORD)
["l'œil"]
>>> regex.findall(r'\w(?:\B\S)*', "J'y suis", flags = regex.V1 | regex.WORD)
["J'y", 'suis']

这是否是预期的行为?(以上所有示例都是使用regex 2.4.106和Python 3.5.2执行的)

1个回答

6

1- 在源文件中,似乎简单地遗漏了右单引号

/* Break between apostrophe and vowels (French, Italian). */
/* WB5a */
if (pos_m1 >= 0 && char_at(state->text, pos_m1) == '\'' &&
  is_unicode_vowel(char_at(state->text, text_pos)))
    return TRUE;

2- Unicode元音字母是用is_unicode_vowel()函数确定的,它会转换成以下列表:

a, à, á, â, e, è, é, ê, i, ì, í, î, o, ò, ó, ô, u, ù, ú, û

因此,LATIN SMALL LIGATURE OE œ 字符不被视为 Unicode 元音:

Py_LOCAL_INLINE(BOOL) is_unicode_vowel(Py_UCS4 ch) {
#if PY_VERSION_HEX >= 0x03030000
    switch (Py_UNICODE_TOLOWER(ch)) {
#else
    switch (Py_UNICODE_TOLOWER((Py_UNICODE)ch)) {
#endif
    case 'a': case 0xE0: case 0xE1: case 0xE2:
    case 'e': case 0xE8: case 0xE9: case 0xEA:
    case 'i': case 0xEC: case 0xED: case 0xEE:
    case 'o': case 0xF2: case 0xF3: case 0xF4:
    case 'u': case 0xF9: case 0xFA: case 0xFB:
        return TRUE;
    default:
        return FALSE;
    }
}

这个漏洞在收到一个bug报告后,现在已经在2016.08.27的regex版本中得到修复。 [_regex.c:#1668]


2
第1点看起来确实像一个漏洞,如果你还没有报告的话,我建议你去报告一下。至于第2点很难说。在unicode.org上搜索“vowel”会得到许多有关亚洲各种语言的结果,但没有关于法语或意大利语的信息。虽然原帖中的例子似乎是正确的,但我没看到附件29专门解决这个问题。 - saulspatz

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