13

rePython 2.7.3 でモジュールを Unicode でエンコードされた Devnagari テキストで使用しようとしています。コードの先頭に追加from __future__ import unicode_literalsしたので、すべての文字列リテラルは Unicode オブジェクトにする必要があります。

ただし、Python の正規表現マッチングで奇妙な問題が発生しています。たとえば、この名前を考えてみましょう:「किशोरी」。これは、ユーザーの 1 人が入力したヒンディー語の (つづりが間違っている) 名前です。ヒンディー語の読者なら誰でも、これを単語として認識するでしょう。

以下は、当然のことながら、一致を返します。

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

しかし、これはしません:

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

いくつかの詳細な調査により、この文字列の文字 0915 (क) の 1 文字だけが \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 テキスト セグメンテーションは次のように述べています。

単語の境界、行の境界、および文の境界は、書記素クラスター内で発生してはなりません。つまり、書記素クラスターは、これらの他の境界を決定するプロセスに関して原子単位である必要があります。

ここで、さらに強調するのは私のものです

単語境界は、 docsでから(またはその逆)\bへの遷移として定義されています。\w\W

正式には、\b は \w と \W 文字 (またはその逆) の間、または \w と文字列の先頭/末尾の間の境界として定義されていることに注意してください。

したがって、1 つの文字を形成するすべてのコードポイントが であるか、\wすべてが\Wです。この場合、"किशोरी"に一致し^\w{6}$ます。


Python 2のドキュメント\wから:

UNICODE が設定されている場合、これは文字 [0-9_] に加えて、Unicode 文字プロパティ データベースで英数字として分類されているものと一致します。

Python 3で:

Unicode 単語文字に一致します。これには、あらゆる言語の単語の一部となるほとんどの文字、数字、アンダースコアが含まれます。

regexドキュメントから:

「単語」文字の定義 ( issue #1693050 ):

「単語」文字の定義が Unicode 用に拡張されました。http://www.unicode.org/reports/tr29/の Unicode 仕様に準拠するようになりました 。これは、\w、\W、\b、\B に適用されます。

unicode.orgU+093FDEVANAGARI VOWEL SIGN Iによると( )は alnum であり、アルファベット順であるため、単語の境界に基づいていない定義に従っている場合でも、regexそれを考慮するのは正しいことです。\w

于 2012-10-05T13:40:22.423 に答える
3

キャラクターマップより:

‍ि

U+093F デバナーガリー母音記号 I

一般的な文字プロパティ

Unicode 以降: 1.1 Unicode カテゴリ:マーク、間隔の組み合わせ

ということで、厳密に言えばこれは文字ではなく、 で\wあっても該当しませんre.UNICODEregexこれらの種類の文字を含めるために、代わりに Unicode 文字プロパティを使用してみることができます。

于 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 に答える