2010-06-29 16 views
7

J'ai une chaîne UTF8 avec combinaison de signes diacritiques. Je veux faire correspondre avec la séquence regex \w. Il correspond aux caractères qui ont des accents, mais pas s'il y a un caractère latin avec des signes diacritiques.Python regex w ne correspond pas à la combinaison de signes diacritiques?

>>> re.match("a\w\w\wz", u"aoooz", re.UNICODE) 
<_sre.SRE_Match object at 0xb7788f38> 
>>> print u"ao\u00F3oz" 
aoóoz 
>>> re.match("a\w\w\wz", u"ao\u00F3oz", re.UNICODE) 
<_sre.SRE_Match object at 0xb7788f38> 
>>> re.match("a\w\w\wz", u"aoo\u0301oz", re.UNICODE) 
>>> print u"aoo\u0301oz" 
aóooz 

(On dirait que le processer SO démarquage est d'avoir des problèmes avec les caractères combinatoires dans ce qui précède, mais il y a une sur la dernière ligne)

Y at-il de toute façon à correspondre avec des diacritiques combinant \w ? Je ne veux pas normaliser le texte parce que ce texte vient du nom de fichier, et je ne veux pas encore avoir à faire une 'normalisation du nom de fichier unicode'. C'est Python 2.5.

Répondre

5

Je viens de remarquer un nouveau paquet "regex" sur pypi. (si je comprends bien, c'est une version de test d'un nouveau paquet qui va un jour remplacer le paquetage stdlib re).

Il semble avoir (entre autres choses) plus de possibilités en ce qui concerne unicode. Par exemple, il prend en charge \X, qui est utilisé pour faire correspondre un seul graphème (qu'il utilise ou non la combinaison). Il prend également en charge la correspondance sur les propriétés, les blocs et les scripts Unicode. Vous pouvez donc utiliser \p{M} pour désigner des marques combinées. Le \X mentionné précédemment est équivalent à \P{M}\p{M}* (un caractère qui n'est PAS une marque de combinaison, suivi par zéro ou plusieurs marques de combinaison).

Notez que cela rend \X plus ou moins l'équivalent unicode de ., pas de \w, donc dans votre cas, \w\p{M}* est ce que vous avez besoin. Il s'agit (pour l'instant) d'un paquet non-stdlib, et je ne sais pas à quel point il est prêt (et il ne s'agit pas d'une distribution binaire), mais vous pouvez essayer, comme Il semble que ce soit la réponse la plus facile/la plus "correcte" à votre question. (sinon, je pense que vous devez utiliser explicitement les gammes de caractères, comme décrit dans mon commentaire à la réponse précédente). Voir aussi this page Voir aussi this page pour plus d'informations sur les expressions régulières Unicode, qui peuvent également contenir des informations utiles pour vous (et peuvent servir de documentation pour certaines des choses implémentées dans le paquetage regex).

1

Vous pouvez utiliser unicodedata.normalize pour composer les signes diacritiques de combinaison en un caractère Unicode.

>>> import re 
>>> from unicodedata import normalize 
>>> re.match(u"a\w\w\wz", normalize("NFC", u"aoo\u0301oz"), re.UNICODE) 
<_sre.SRE_Match object at 0x00BDCC60> 

Je sais que vous avez dit que vous ne vouliez pas normaliser, mais je ne pense pas qu'il y aura un problème avec cette solution, comme vous ne normalisant la chaîne à faire correspondre, et ne pas pour changer le nom de fichier lui-même ou quelque chose.

+1

Oui, cela me dira si j'ai un match, mais après avoir fait le match, je sors les groupes correspondants et ensuite je fais des trucs avec eux. Si j'ai utilisé votre approche, alors les octets que j'ai après ne seraient pas les mêmes octets que dans le nom de fichier – Rory

+0

je vois. Savez-vous si les cordes sont cohérentes dans leur utilisation de la combinaison des signes diacritiques (combinant toujours, ou au moins toujours en combinant ou non dans une seule chaîne)? Si tel est le cas, vous pouvez normaliser les résultats à NFC ou NFD à nouveau si nécessaire. Sinon, je pense que vous devrez recourir à des astuces pour détecter la position de la combinaison de signes diacritiques dans la chaîne d'origine et essayer d'utiliser cette information pour décomposer uniquement les caractères nécessaires (ce qui serait bien plus pas du tout). – Steven

+0

Ou peut-être simplement changer l'expression et utiliser les plages pour les diacritiques de combinaison qui vous intéressent, et utiliser quelque chose comme \ w [\ u0300- \ u036F]? au lieu de simplement \ w – Steven