13

我正在尝试将rePython 2.7.3 中的模块与 Unicode 编码的 Devnagari 文本一起使用。我已添加from __future__ import unicode_literals到代码的顶部,因此所有字符串文字都应该是 unicode 对象。

但是,我在 Python 的正则表达式匹配方面遇到了一些奇怪的问题。例如,考虑这个名字:“किशोरी”。这是一个(拼写错误的)名称,在印地语中,由我的一个用户输入。任何印地语读者都会认出这是一个词。

以下返回一个匹配,因为它应该:

re.search("^[\w\s][\w\s]*","किशोरी",re.UNICODE)

但这不会:

re.search("^[\w\s][\w\s]*$","किशोरी",re.UNICODE)

一些探索表明,这个字符串中只有一个字符,字符 0915 (क),被识别为属于 \w 字符类。这是不正确的,因为“派生核心属性”上的 Unicode 字符数据库文件将该字符串中的其他字符(我没有检查所有字符)列为字母字符 - 确实如此。

这只是 Python 实现中的一个错误吗?我可以通过手动将所有 Devnagari 字母数字字符定义为字符范围来解决这个问题,但这会很痛苦。还是我做错了什么?

4

3 回答 3

12

这是模块中的一个错误,它已在re模块中修复:regex

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import unicodedata
import re
import regex  # $ pip install regex

word = "किशोरी"


def test(re_):
    assert re_.search("^\\w+$", word, flags=re_.UNICODE)

print([unicodedata.category(cp) for cp in word])
print(" ".join(ch for ch in regex.findall("\\X", word)))
assert all(regex.match("\\w$", c) for c in ["a", "\u093f", "\u0915"])

test(regex)
test(re)  # fails

输出显示 中有 6 个代码点"किशोरी",但只有 3 个用户感知字符(扩展字形簇)。在一个字符内打断一个单词是错误的。 Unicode 文本分割说:

单词边界、行边界和句子边界不应出现在字素簇内:换句话说,就确定这些其他边界的过程而言,字素簇应该是一个原子单元。

在这里,进一步强调是我的

单词边界在文档\b中定义为从\w\W(或反向)的转换:

请注意,正式地,\b 被定义为 \w 和 \W 字符之间的边界(反之亦然),或 \w 和字符串的开头/结尾之间,...

因此,形成单个字符的所有代码点要么是,要么\w都是\W. 在这种情况下"किशोरी"匹配^\w{6}$.


来自Python 2 中的文档\w

如果设置了 UNICODE,这将匹配字符 [0-9_] 加上Unicode 字符属性数据库中分类为字母数字的任何内容。

Python 3中:

匹配 Unicode 单词字符;这包括可以成为任何语言中单词一部分的大多数字符,以及数字和下划线。

来自regex文档:

'word' 字符的定义(问题 #1693050):

“单词”字符的定义已针对 Unicode 进行了扩展。它现在符合 http://www.unicode.org/reports/tr29/上的 Unicode 规范。这适用于 \w、\W、\b 和 \B。

根据unicode.org U+093F( DEVANAGARI VOWEL SIGN I)是 alnum 和 alphabetic 因此即使我们遵循不基于单词边界的定义,regex考虑它也是正确的。\w

于 2012-10-05T13:40:22.423 回答
3

从字符映射:

‍ि

U+093F 梵音元音符号 I

一般字符属性

在 Unicode 自:1.1 Unicode 类别:标记、间距组合

所以,从技术上讲,这不是一封信,\w即使是re.UNICODE. 您可以尝试使用regexUnicode 字符属性来包含这些类型的字符。

于 2012-10-05T13:07:25.110 回答
2

我测试了以下内容:

import unicodedata
for c in "किशोरी":
    print unicodedata.category(c)
    print unicodedata.name(c)

在我的情况下显示:

Lo
DEVANAGARI LETTER KA
Mc
DEVANAGARI VOWEL SIGN I
Lo
DEVANAGARI LETTER SHA
Mc
DEVANAGARI VOWEL SIGN O
Lo
DEVANAGARI LETTER RA
Mc
DEVANAGARI VOWEL SIGN II

Unicode 的东西很难调试,因为复制和粘贴会弄乱数据,而且我不懂印地语。但是在某些语言中,您可以在 unicode 中以不同的方式对字符进行编码。是否有可能,您必须在匹配之前以某种方式规范化您的字符串?对我来说,元音符号不匹配看起来没问题\w

于 2012-10-05T13:09:06.857 回答