2010-09-27 6 views
6

devo stringhe che sono multilingue consistere in entrambe le lingue che utilizzano gli spazi come separatore di parola (inglese, francese, ecc) e le lingue che non (cinese, giapponese, coreano).Python: un modo per eseguire questo split "ibrido"() su stringhe multilingue (ad esempio cinese e inglese)?

Data una tale stringa, voglio separare la parte inglese/francese/etc in parole usando spazi bianchi come separatore e separare la parte cinese/giapponese/coreana in singoli caratteri.

e voglio mettere di tutte quelle componenti separati in una lista.

Alcuni esempi probabilmente chiarire questo punto:

Caso 1: solo in inglese stringa. Questo caso è facile:

>>> "I love Python".split() 
['I', 'love', 'Python'] 

Caso 2: cinese sola stringa:

>>> list(u"我爱蟒蛇") 
[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7'] 

In questo caso posso trasformare la stringa in un elenco di caratteri cinesi. Ma all'interno della lista sto ottenendo rappresentazioni unicode:

[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7'] 

Come faccio a farlo per visualizzare i caratteri effettivi invece del unicode? Qualcosa di simile:

['我', '爱', '蟒', '蛇'] 

??

Caso 3: Un mix di inglese & cinese:

voglio trasformare una stringa di input come ad esempio

"我爱Python" 

e lo trasforma in una lista come questa:

['我', '爱', 'Python'] 

È possibile fare qualcosa del genere?

+0

Purtroppo, c'è un misfeature in corrente di Python il modulo 're' che preclude' re.split() 'a dividere su corrispondenze a lunghezza zero: http://stackoverflow.com/questions/2713060/why-doesnt-pythons-re-split-split-on-zero-length -matches - quindi non puoi usare espressioni regolari in Python per questo direttamente. –

+1

Coreano utilizza spazi bianchi per la separazione delle parole. – Leovt

risposta

3

Ho pensato di mostrare anche l'approccio regex. Non mi sembra giusto, ma è soprattutto perché tutte le stranezze specifiche della lingua che ho visto mi preoccupano che un'espressione regolare non sia abbastanza flessibile per tutte loro, ma potresti non aver bisogno di alcuna di quella. (In altre parole - sovraprogettazione.)

# -*- coding: utf-8 -*- 
import re 
def group_words(s): 
    regex = [] 

    # Match a whole word: 
    regex += [ur'\w+'] 

    # Match a single CJK character: 
    regex += [ur'[\u4e00-\ufaff]'] 

    # Match one of anything else, except for spaces: 
    regex += [ur'[^\s]'] 

    regex = "|".join(regex) 
    r = re.compile(regex) 

    return r.findall(s) 

if __name__ == "__main__": 
    print group_words(u"Testing English text") 
    print group_words(u"我爱蟒蛇") 
    print group_words(u"Testing English text我爱蟒蛇") 

In pratica, si sarebbe probabilmente desidera compilare solo l'espressione regolare una volta, non su ogni chiamata. Ancora una volta, la compilazione dei dettagli del raggruppamento dei personaggi dipende da te.

+0

@Glenn Maynard. Grazie mille. Questo è esattamente ciò di cui ho bisogno. Potresti darmi dei consigli su dove cercare l'"intervallo" unicode per varie lingue? – Continuation

+0

Non proprio. I caratteri non si raggruppano bene per lingua; probabilmente puoi individuare le gamme maggiori semplicemente abbastanza. –

+0

-1 @Glenn Maynard: nella locale "C", fallisce su caratteri alfabetici non ASCII non CJK, ad es. come trovato in francese [requisito OP], tedesco, russo - "u" München "' -> '[u'M ', u' \ xfc ', u'nchen']'. Sfortunatamente questo problema può essere risolto usando il flag 're.UNICODE' ma questo fa \ \. \' 'Corrisponde alla maggior parte dei caratteri CJK (categoria' Lo'). –

2

formattazione di una lista figurano i repr dei suoi componenti. Se si desidera visualizzare le stringhe in modo naturale piuttosto che fuggire, è necessario formattarlo da soli. (repr dovrebbe non essere scappavano questi personaggi; repr(u'我') dovrebbe restituire "u'我'", non "u'\\u6211' A quanto pare questo accade in Python 3;. Solo 2.x è bloccato con l'inglese-centric fuga per le stringhe Unicode.)

A base l'algoritmo che puoi usare è assegnare una classe di caratteri a ciascun personaggio, quindi raggruppare le lettere per classe. Il codice di avviamento è sotto.

Non ho usato un doctest per questo perché ho riscontrato alcuni problemi di codifica dispari che non voglio esaminare (fuori ambito). Dovrai implementare una corretta funzione di raggruppamento.

Si noti che se si sta utilizzando questo per il ritorno a capo, ci sono altre considerazioni per-lingua. Ad esempio, non vuoi rompere su spazi non interrotti; vuoi rompere i trattini; per il giapponese non vuoi separarti き ゅ; e così via.

# -*- coding: utf-8 -*- 
import itertools, unicodedata 

def group_words(s): 
    # This is a closure for key(), encapsulated in an array to work around 
    # 2.x's lack of the nonlocal keyword. 
    sequence = [0x10000000] 

    def key(part): 
     val = ord(part) 
     if part.isspace(): 
      return 0 

     # This is incorrect, but serves this example; finding a more 
     # accurate categorization of characters is up to the user. 
     asian = unicodedata.category(part) == "Lo" 
     if asian: 
      # Never group asian characters, by returning a unique value for each one. 
      sequence[0] += 1 
      return sequence[0] 

     return 2 

    result = [] 
    for key, group in itertools.groupby(s, key): 
     # Discard groups of whitespace. 
     if key == 0: 
      continue 

     str = "".join(group) 
     result.append(str) 

    return result 

if __name__ == "__main__": 
    print group_words(u"Testing English text") 
    print group_words(u"我爱蟒蛇") 
    print group_words(u"Testing English text我爱蟒蛇") 
0

Modificato soluzione di Glenn far cadere simboli e di lavoro per gli alfabeti russo, francese, ecc:

def rec_group_words(): 
    regex = [] 

    # Match a whole word: 
    regex += [r'[A-za-z0-9\xc0-\xff]+'] 

    # Match a single CJK character: 
    regex += [r'[\u4e00-\ufaff]'] 

    regex = "|".join(regex) 
    return re.compile(regex) 
1

In Python 3, si divide anche il numero se si ha bisogno.

def spliteKeyWord(str): 
    regex = r"[\u4e00-\ufaff]|[0-9]+|[a-zA-Z]+\'*[a-z]*" 
    matches = re.findall(regex, str, re.UNICODE) 
    return matches 

print(spliteKeyWord("Testing English text我爱Python123")) 

=> [ 'Test', 'English', 'testo', '我', '爱', 'Python', '123']

Problemi correlati