質問

私はどんなものを持っています

a = "बिक्रम मेरो नाम हो"

のようなことを達成したいです

a[0] = बि
a[1] = क्र
a[3] = म

しかし、मが4バイトをかけ、बिが8バイトを取るので、私はそれをまっすぐに到達することができません。それで、それを達成するために何ができるでしょうか? Pythonで。

役に立ちましたか?

解決

テキストをグラフェメクラスターに分割するためのアルゴリズムは、 Unicode Annex 29, 、セクション3.1。ここでは完全なアルゴリズムを実装するつもりはありませんが、Devanagariのケースを処理する方法を大まかに示してから、自分で別館を読んで、実装する必要があるものを確認できます。

unicodedata モジュール グラフェムクラスターを検出するために必要な情報が含まれています。

>>> import unicodedata
>>> a = "बिक्रम मेरो नाम हो"
>>> [unicodedata.name(c) for c in a]
['DEVANAGARI LETTER BA', 'DEVANAGARI VOWEL SIGN I', 'DEVANAGARI LETTER KA', 
 'DEVANAGARI SIGN VIRAMA', 'DEVANAGARI LETTER RA', 'DEVANAGARI LETTER MA',
 'SPACE', 'DEVANAGARI LETTER MA', 'DEVANAGARI VOWEL SIGN E',
 'DEVANAGARI LETTER RA', 'DEVANAGARI VOWEL SIGN O', 'SPACE',
 'DEVANAGARI LETTER NA', 'DEVANAGARI VOWEL SIGN AA', 'DEVANAGARI LETTER MA',
 'SPACE', 'DEVANAGARI LETTER HA', 'DEVANAGARI VOWEL SIGN O']

Devanagariでは、各Graphemeクラスターは、最初の文字、Virama(母音キラー)と文字のオプションのペア、およびオプションの母音サインで構成されています。正規表現表記ではそうなるでしょう LETTER (VIRAMA LETTER)* VOWEL?. 。あなたはどちらがどちらであるかを知ることができます Unicodeカテゴリ 各コードポイントについて:

>>> [unicodedata.category(c) for c in a]
['Lo', 'Mc', 'Lo', 'Mn', 'Lo', 'Lo', 'Zs', 'Lo', 'Mn', 'Lo', 'Mc', 'Zs',
 'Lo', 'Mc', 'Lo', 'Zs', 'Lo', 'Mc']

文字はカテゴリです Lo (文字、その他)、母音の標識はカテゴリーです Mc (マーク、間隔を組み合わせて)、Viramaはカテゴリです Mn (マーク、非歩行)、スペースはカテゴリです Zs (セパレーター、スペース)。

したがって、グラフェムクラスターを分割するための大まかなアプローチが次のとおりです。

def splitclusters(s):
    """Generate the grapheme clusters for the string s. (Not the full
    Unicode text segmentation algorithm, but probably good enough for
    Devanagari.)

    """
    virama = u'\N{DEVANAGARI SIGN VIRAMA}'
    cluster = u''
    last = None
    for c in s:
        cat = unicodedata.category(c)[0]
        if cat == 'M' or cat == 'L' and last == virama:
            cluster += c
        else:
            if cluster:
                yield cluster
            cluster = c
        last = c
    if cluster:
        yield cluster

>>> list(splitclusters(a))
['बि', 'क्र', 'म', ' ', 'मे', 'रो', ' ', 'ना', 'म', ' ', 'हो']

他のヒント

だから、あなたはこのようなことを達成したいと思っています

a[0] = बि a[1] = क्र a[3] = म

私のアドバイスは、文字列のインデックスが画面に表示される文字に対応するという考えを捨てることです。 Devanagariと他のいくつかのスクリプトは、ラテン語のキャラクターで育ったプログラマーとうまく機能しません。 Unicode Standard Chapter 9を読むことをお勧めします(こちらから入手できます).

あなたがやろうとしていることは、文字列をグラフェメクラスターに分割することです。文字列のインデックス作成自体は、これを行わせません。ハングルは、文字列のインデックス作成で機能しない別のスクリプトですが、キャラクターを組み合わせることで、スペイン語と同じくらい馴染みのあるものでさえ問題を引き起こします。

これを達成するには、ICUなどの外部ライブラリが必要になります(自由時間が多い場合を除きます)。 ICUにはPythonバインディングがあります。

>>> a = u"बिक्रम मेरो नाम हो"
>>> import icu
    # Note: This next line took a lot of guesswork.  The C, C++, and Java
    # interfaces have better documentation.
>>> b = icu.BreakIterator.createCharacterInstance(icu.Locale())
>>> b.setText(a)
>>> i = 0
>>> for j in b:
...     s = a[i:j]
...     print '|', s, len(s)
...     i = j
... 
| बि 2
| क् 2
| र 1
| म 1
|   1
| मे 2
| रो 2
|   1
| ना 2
| म 1
|   1
| हो 2

これらの「文字」の一部(グラフェメクラスター)の長さ2、および一部の長さは長さ1の理由に注意してください。これが文字列のインデックス作成に問題がある理由です。テキストファイルからgraphemeクラスター#69450を取得する場合は、線形スキャンする必要があります。ファイル全体とカウントを通じて。したがって、あなたのオプションは次のとおりです。

  • インデックスを作成する(ちょっとクレイジー...)
  • すべての文字の境界を破ることができないことを理解してください。 Break Iteratorオブジェクトは前方と後方の両方を進むことができるため、文字列の最初の140文字を抽出する必要がある場合は、インデックス140を見て繰り返します 後方 以前のGrapheme Cluster Breakに、面白いテキストになりません。 (さらに良いことに、aを使用できます ワードブレイク 適切なロケールのための反復器。)このレベルの抽象化(文字反復因子など)を使用することの利点は、使用するエンコードがもはや問題ではないことです。UTF-8、UTF-16、UTF-32を使用できます。ただ機能します。まあ、ほとんどが機能します。

でこれを達成できます 単純な正規表現 サポートするエンジン用 \X

デモ

残念ながら、PythonのRE サポートしていません x grapheme一致。

幸いなことに、提案された代替品、 正規表現, 、サポートしています \X:

>>> a = "बिक्रम मेरो नाम हो"
>>> regex.findall(r'\X', a)
['बि', 'क्', 'र', 'म', ' ', 'मे', 'रो', ' ', 'ना', 'म', ' ', 'हो']

純粋なパイソンライブラリが呼ばれています uniseg これは、説明された動作を提供するグラフェムクラスターイテレーターを含む多くのユーティリティを提供します。

>>> a = u"बिक्रम मेरो नाम हो"
>>> from uniseg.graphemecluster import grapheme_clusters
>>> for i in grapheme_clusters(a): print(i)
... 
बि
क्
र
म

मे
रो

ना
म

हो

で説明されている完全なUnicodeテキストセグメンテーションアルゴリズムを実装すると主張しています http://www.unicode.org/reports/tr29/tr29-21.html.

Hangulのようなインドおよび非ラテンスクリプトは、一般に、文字列インデックスをコードポイントに一致させるという考えに従いません。一般的に、インドのスクリプトを使用して動作する痛みです。ほとんどの文字は2バイトで、いくつかの珍しい文字が3つに伸びています。 Dravidianでは、定義された順序ではありません。を参照してください ユニコード仕様 詳細については。

そうは言っても、チェックしてください ここ C ++を使用したUnicodeとPythonに関するいくつかのアイデアについて。

最後に、言ったように ディートリッヒ, 、チェックアウトしたいかもしれません ICU それも。それぞれICU4CとICU4Jを介してC/C ++とJavaで利用可能なバインディングがあります。いくつかの学習曲線が関係しているので、私はあなたが脇に置くことをお勧めします いくつか それのための時間の負荷。 :)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top