我试图使用Python 2.7.3中的re
模块和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字符数据库file on "derived core properties"将此字符串中的其他字符(我没有全部检查过)列为字母字符串 - 事实上它们确实如此。
这只是Python实现中的一个错误吗?我可以通过手动将所有Devnagari字母数字字符定义为字符范围来解决这个问题,但这会很痛苦。或者我做错了什么?
答案 0 :(得分:7)
这是一个bug in the re
module,它已在regex
module中修复:
# -*- 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 Text Segmentation说:
词边界,行边界和句子边界不应该 在字形集群中发生:换言之,字形集群 应该是关于确定过程的原子单位 这些其他界限。
这里进一步强调我的
字边界\b
被定义为the docs中从\w
到\W
(或相反)的转换:
注意,正式地,\ b被定义为\ w和a之间的边界 \ W字符(反之亦然),或\ w与\ n开头/结尾之间 字符串,......
因此,构成单个字符的所有代码点都是\w
,或者它们都是\W
。
在这种情况下,"किशोरी"
与^\w{6}$
匹配。
来自the docs for \w
in Python 2:
Python 3中的如果设置了UNICODE,则会匹配字符[0-9_] plus 在Unicode字符中被归类为字母数字的任何内容 属性数据库</ em>。
:
匹配Unicode字符;这个包含了大多数字符 可以是任何语言中的单词的一部分,以及数字和 下划线。
来自regex
文档:
'word'字符的定义(issue #1693050):
为Unicode扩展了“单词”字符的定义。它现在符合Unicode规范 http://www.unicode.org/reports/tr29/。这适用于\ w,\ W,\ b和 \乙
根据unicode.org U+093F
(DEVANAGARI VOWEL SIGN I
)是alnum和字母,因此即使我们遵循不基于单词边界的定义,regex
也可以考虑它\w
。
答案 1 :(得分:3)
来自角色地图:
ि
U + 093F DEVANAGARI VOWEL SIGN I
一般字符属性
在Unicode中:1.1 Unicode类别:标记,间距合并
因此,从技术上讲,这不是一封信,即使\w
也不属于re.UNICODE
。您可以尝试使用带有Unicode字符属性的regex
来包含这些类型的字符。
答案 2 :(得分: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
不匹配。