簡體   English   中英

Python unicode正則表達式匹配失敗了一些unicode字符-bug或錯誤?

[英]Python unicode regular expression matching failing with some unicode characters -bug or mistake?

我試圖在Python 2.7.3中使用帶有Unicode編碼的Devnagari文本的re模塊。 我已將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字母數字字符定義為字符范圍來解決這個問題,但這會很痛苦。 或者我做錯了什么?

這是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+093FDEVANAGARI VOWEL SIGN I可以是alnum和字母所以regex也是正確的考慮\\w即使我們遵循並非基於單詞邊界定義。

從字符圖:

ि

U + 093F DEVANAGARI VOWEL SIGN I

一般字符屬性

在Unicode中:1.1 Unicode類別: Mark,Spacing Combining

因此,從技術上講,這不是一封信,即使使用re.UNICODE也不屬於\\w 您可以嘗試使用帶有Unicode字符屬性的regex來包含這些類型的字符。

我測試了以下內容:

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不匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM