Domanda

ho qualcosa di simile

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

Voglio realizzare qualcosa di simile

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

ma come ? prende 4 byte mentre ?? prende 8 byte Io non sono in grado di arrivare a quel diritto. Così che cosa potrebbe essere fatto per raggiungere questo? In Python.

È stato utile?

Soluzione

L'algoritmo per il testo suddivisione in cluster grafema è dato in Unicode allegato 29 , sezione 3.1. Io non ho intenzione di implementare l'algoritmo di piena per voi qui, ma io vi mostrerò all'incirca come gestire il caso di Devanagari, e poi si può leggere l'allegato per te stesso e vedere cos'altro è necessario implementare.

Il unicodedata modulo contiene le informazioni necessarie per rilevare i cluster grafema.

>>> 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, ogni cluster grafema è costituito da una lettera iniziale, coppie opzionali di virama (vocale assassino) e lettera, e un segno di vocale opzionale. Nel regolare la notazione espressione che sarebbe LETTER (VIRAMA LETTER)* VOWEL?. Si può dire che è che, cercando il Unicode categoria per ciascun punto di codice:

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

Le lettere sono categoria Lo (Lettera, Altro), segni vocalici sono di categoria Mc (Mark, spaziatura combinazione), virama è categoria Mn (Mark, senza spaziatura) e gli spazi sono di categoria Zs (separatore, Spazio).

Quindi, ecco un approccio di massima per dividere i cluster grafema:

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

Altri suggerimenti

Quindi, si vuole raggiungere qualcosa di simile

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

Il mio consiglio è quello di abbandonare l'idea che la stringa di indicizzazione corrisponde ai caratteri che vedi sullo schermo. Devanagari, così come molti altri script, non giocare bene con i programmatori che sono cresciuti con caratteri latini. Suggerisco di leggere il capitolo standard Unicode 9 ( disponibile qui ).

Sembra che ciò che si sta cercando di fare è rompere una stringa in cluster grafema. String indicizzazione di per sé non ti consente di fare questo. Hangul è un altro script che gioca male con indicizzazione stringa, anche se con i caratteri che conciliano, anche qualcosa di familiare come spagnolo causerà problemi.

Si avrà bisogno di una libreria esterna come ICU per raggiungere questo obiettivo (a meno che non hai un sacco di tempo libero). ICU ha binding 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

Si noti come alcuni di questi "personaggi" (cluster) grafema avere una lunghezza 2, e alcuni hanno lunghezza 1. Questo è il motivo per cui stringa di indicizzazione è problematico: se voglio ottenere grafema grappolo # 69450 da un file di testo, poi ho a linearmente eseguire la scansione attraverso l'intero file e contare. Quindi, le opzioni sono:

  • Crea un indice (una specie di pazzo ...)
  • Basta rendersi conto che non si può rompere su ogni confine carattere. L'oggetto pausa iteratore è in grado di andare sia in avanti che all'indietro, quindi se avete bisogno di estrarre i primi 140 caratteri di una stringa, poi si guarda indice 140 e iterare all'indietro al precedente rottura grappolo grafema, in questo modo non si finisce con testo divertente. (. Meglio ancora, è possibile utilizzare un pausa parola iteratore per la locale appropriata) Il vantaggio di utilizzare questo livello di astrazione (iteratori carattere e simili) è che non ha più importanza che codificano per usare: è possibile utilizzare UTF-8, UTF-16, UTF-32 e funziona tutto solo. Beh, funziona per lo più.

È possibile raggiungere questo obiettivo con un semplice espressione regolare per qualsiasi motore che supporta \X

Demo

Purtroppo, re di Python non supporta il \ X grafema partita.

Per fortuna, la sostituzione proposta, regex , fa supporto \X:

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

C'è una biblioteca pura-Python chiamato uniseg che fornisce una serie di utility tra cui un cluster grafema iteratore che fornisce il comportamento descritto:

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

मे
रो

ना
म

हो

Si sostiene di implementare l'algoritmo di testo Unicode completo di segmentazione descritto nella http: // www.unicode.org/reports/tr29/tr29-21.html .

Indic e gli script non latini come Hangul non seguono generalmente l'idea di abbinare gli indici di stringa di punti di codice. E 'generalmente un dolore lavorare con gli script indiane. La maggior parte dei personaggi sono due byte con alcuni tra quelli rari che si estendono in tre. Con dravidica, non è un ordine definito. Vedere la Unicode specifica per ulteriori dettagli.

Detto questo, di controllo qui per alcune idee su Unicode e pitone con C ++.

Infine, come detto da Dietrich , si potrebbe desiderare di controllare ICU troppo. Ha attacchi disponibili per C / C ++ e Java tramite icu4c e ICU4J rispettivamente. C'è un po 'curva di apprendimento coinvolti, quindi vi suggerisco di mettere da parte alcuni un sacco di tempo per questo. :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top