2010-09-27 5 views
6

J'ai des chaînes multilingues composées des deux langues qui utilisent des espaces comme séparateur de mots (anglais, français, etc.) et des langues qui ne le sont pas (chinois, japonais, coréen). Je souhaite séparer la partie anglais/français/etc en mots utilisant un espace comme séparateur et séparer la partie chinoise/japonaise/coréenne en caractères individuels.Python: un moyen d'effectuer cette division "hybride"() sur des chaînes multilingues (par exemple chinois et anglais)?

Et je veux mettre de tous ces composants séparés dans une liste.

Quelques exemples seraient sans doute que cela soit clair:

Cas 1: chaîne en anglais seulement. Ce cas est facile:

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

Cas n ° 2: chaîne chinoise seule:

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

Dans ce cas, je peux transformer la chaîne en une liste de caractères chinois. Mais, dans la liste que je reçois des représentations unicode:

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

Comment puis-je obtenir pour afficher les caractères réels au lieu de l'unicode? Quelque chose comme:

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

??

Cas n ° 3: Un mélange d'anglais & chinois:

Je veux transformer une chaîne d'entrée tels que

"我爱Python" 

et il se transforme en une liste comme ceci:

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

Est-il possible de faire quelque chose comme ça?

+0

Malheureusement, il y a un disfonctionnement dans le courant de Python Module 're' qui empêche' re.split() 'de se séparer sur des correspondances de longueur nulle: http://stackoverflow.com/questions/2713060/why-doesnt-pythons-re-split-split-on-zero-length -matches - vous ne pouvez donc pas utiliser directement les expressions régulières dans Python. –

+1

Le coréen utilise des espaces pour la séparation des mots. – Leovt

Répondre

3

Je pensais aussi montrer l'approche regex. Cela ne me semble pas normal, mais c'est surtout parce que toutes les bizarreries i18n spécifiques à la langue que j'ai vues me font craindre qu'une expression régulière ne soit pas assez flexible pour chacune d'entre elles - mais vous pourriez bien n'en avoir aucune de ça. (En d'autres termes - surdimensionnement.)

# -*- 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我爱蟒蛇") 

Dans la pratique, vous voudrez probablement seulement compiler l'expression rationnelle une fois, pas sur chaque appel. Encore une fois, il vous appartient de remplir les détails du groupement de caractères.

+0

@Glen Maynard. Merci beaucoup. C'est exactement ce dont j'ai besoin. Pourriez-vous me donner des indications sur où chercher la "gamme" unicode pour différentes langues? – Continuation

+0

Pas vraiment. Les personnages ne se regroupent pas bien par langue; vous pouvez probablement choisir les plages majeures assez directement. –

+0

-1 @Genn Maynard: Dans les paramètres régionaux "C", cela échoue sur les alphabets non-ASCII non-CJK, par ex. comme trouvé en français [exigence d'OP], allemand, russe - 'u" München "' -> '[u'M ', u' \ xfc ', u'nchen']'. Malheureusement, ceci peut être corrigé en utilisant le drapeau 're.UNICODE' mais cela fait que' \ w' correspond à la plupart des caractères CJK (catégorie 'Lo'). –

2

Le formatage d'une liste montre le repr de ses composants. Si vous souhaitez afficher les chaînes naturellement plutôt que d'être échappées, vous devrez le formater vous-même. (repr devrait pas échapperont ces personnages, repr(u'我') devrait revenir "u'我'", pas "u'\\u6211' Apparemment, cela ne se produit en Python 3,. Que 2.x est coincé avec la fuite en anglais centrée sur des chaînes Unicode.)

A base L'algorithme que vous pouvez utiliser est l'assignation d'une classe de caractères à chaque caractère, puis le regroupement des lettres par classe. Le code de démarrage est ci-dessous.

Je n'ai pas utilisé de doctest pour cela parce que j'ai rencontré des problèmes de codage bizarre que je ne veux pas examiner (hors champ). Vous devrez implémenter une fonction de regroupement correcte.

Notez que si vous utilisez cette option pour le retour à la ligne, il existe d'autres considérations par langue. Par exemple, vous ne voulez pas casser des espaces insécables; vous voulez rompre les traits d'union; pour le japonais, vous ne voulez pas diviser き ゅ; etc.

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

solution modifiée de Glenn à déposer des symboles et de travail pour les alphabets russes, français, etc:

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

En Python 3, il divise aussi le nombre si vous avez besoin.

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

=> [ 'Testing', 'anglais', 'texte', '我', '爱', 'Python', '123']

Questions connexes