Frage

Ich habe so etwas wie

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

Ich möchte so etwas erreichen wie

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

Aber wie म 4 Bytes nimmt, während बि 8 Bytes nimmt, kann ich nicht in die Gerade kommen. Was könnte also getan werden, um das zu erreichen? In Python.

War es hilfreich?

Lösung

Der Algorithmus zur Aufteilung von Text in Graphem -Cluster ist in angegeben Unicode Anhang 29, Abschnitt 3.1. Ich werde hier nicht den vollständigen Algorithmus für Sie implementieren, aber ich zeige Ihnen grob, wie Sie mit dem Fall von Devanagari umgehen können, und dann können Sie das Anhang für sich selbst lesen und sehen, was Sie sonst noch implementieren müssen.

Das unicodedata Modul Enthält die Informationen, die Sie benötigen, um die Graphem -Cluster zu erkennen.

>>> 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']

In Devanagari besteht jedes Graphem -Cluster aus einem ersten Buchstaben, optionalen Virama -Paaren (Vokalkiller) und einem Buchstaben sowie einem optionalen Vokalzeichen. In regelmäßiger Ausdrucksnotation wäre das LETTER (VIRAMA LETTER)* VOWEL?. Sie können erkennen, welches ist, indem Sie die nachschlagen Unicode -Kategorie Für jeden Codepunkt:

>>> [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']

Briefe sind Kategorie Lo (Brief, andere), Vokalzeichen sind Kategorie Mc (Mark, Abstand Kombination), Virama ist Kategorie Mn (Mark, Nonspacing) und Räume sind Kategorie Zs (Separator, Raum).

Hier finden Sie einen groben Ansatz, um die Graphem -Cluster aufzuteilen:

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))
['बि', 'क्र', 'म', ' ', 'मे', 'रो', ' ', 'ना', 'म', ' ', 'हो']

Andere Tipps

Sie möchten also so etwas erreichen

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

Mein Rat ist, die Idee, dass die String -Indexierung den Zeichen, die Sie auf dem Bildschirm sehen, zu entsprechen, aufzugeben. Devanagari sowie mehrere andere Skripte spielen nicht gut mit Programmierern, die mit lateinischen Charakteren aufgewachsen sind. Ich schlage vor, den Unicode -Standard zu lesen, Kapitel 9 (hier verfügbar).

Es sieht so aus, als ob Sie versuchen, eine Zeichenfolge in Graphem -Cluster zu unterteilen. Die String -Indexierung von selbst lässt Sie dies nicht tun. Hangul ist ein weiteres Skript, das mit der String -Indexierung schlecht spielt, obwohl mit dem Kombinieren von Charakteren, selbst etwas, das so Vertraut ist wie Spanisch, Probleme verursacht.

Sie benötigen eine externe Bibliothek wie die Intensivstation, um dies zu erreichen (es sei denn, Sie haben viel Freizeit). Die Intensivstation hat Python -Bindungen.

>>> 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

Beachten Sie, wie einige dieser "Zeichen" (Graphem -Cluster) Länge 2 haben, und einige haben Länge 1. Aus diesem Grund ist die String -Indexierung problematisch: Wenn ich Graphem -Cluster Nr. 69450 aus einer Textdatei abrufen möchte, muss ich linear scannen durch die gesamte Datei und zählen. Ihre Optionen sind also:

  • Erstellen Sie einen Index (irgendwie verrückt ...)
  • Erkenne einfach, dass du nicht jede Charaktergrenze brechen kannst. Das Break -Iterator -Objekt kann sowohl nach vorne als auch rückwärts gehen rückwärts Im vorherigen Graphem -Cluster -Break haben Sie auf diese Weise keinen lustigen Text. (Besser noch können Sie a verwenden Wortpause Iterator für das entsprechende Gebietsschema.) Der Vorteil der Verwendung dieser Abstraktionsebene (Charakter-Iteratoren und dergleichen) besteht funktioniert nur. Nun, meistens funktioniert.

Sie können dies mit a erreichen Einfache Regex Für jeden Motor, der unterstützt \X

Demo

Leider, Pythons Re unterstützt nicht Das x Graphem -Match.

Glücklicherweise der vorgeschlagene Ersatz, Regex, unterstützt \X:

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

Es gibt eine reine Python-Bibliothek namens uniseg Dies liefert eine Reihe von Dienstprogrammen, einschließlich eines Graphem -Cluster -Iterators, das das von Ihnen beschriebene Verhalten liefert:

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

मे
रो

ना
म

हो

Es wird behauptet, den in der in der beschriebenen vollständigen Unicode -Text -Segmentierungsalgorithmus zu implementieren http://www.unicode.org/reports/tr29/tr29-21.html.

Indic- und nicht lateinische Skripte wie Hangul folgen im Allgemeinen nicht der Idee, Stringindizes mit Codepunkten abzustimmen. Es ist im Allgemeinen ein Schmerz, mit Indic -Skripten zu arbeiten. Die meisten Charaktere sind zwei Bytes mit einigen seltenen, die sich in drei erstrecken. Mit Dravidian ist es keine definierte Reihenfolge. Siehe das Unicode -Spezifikation für mehr Details.

Das heißt, überprüfen Sie hier Für einige Ideen zu Unicode und Python mit C ++.

Schließlich, wie gesagt von Dietrich, Sie möchten vielleicht auschecken ICU zu. Es verfügt über Bindungen für C/C ++ und Java über ICU4C bzw. ICU4J. Es ist einige Lernkurve erforderlich, daher schlage ich vor, dass Sie beiseite gelegt werden etwas Viel Zeit dafür. :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top