2010-06-29 20 views
7

Tengo una cuerda UTF8 con combinación de signos diacríticos. Quiero que coincida con la secuencia de expresiones regulares \w. Coincide con los caracteres que tienen acentos, pero no si se trata de un personaje latino que combina signos diacríticos.Python regex w no coincide con la combinación de diacríticos?

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

(se parece a la Procesadora SO rebaja está teniendo problemas con los signos diacríticos que combinan en lo anterior, pero hay una en la última línea)

¿Hay alguna forma para que coincida con la combinación de diacríticos \w ? No quiero normalizar el texto porque este texto proviene de un nombre de archivo, y no quiero tener que hacer un 'nombre completo de archivo de normalización Unicode' todavía. Esto es Python 2.5.

Respuesta

5

Acabo de notar un nuevo paquete "regex" en pypi. (si lo entiendo correctamente, es una versión de prueba de un nuevo paquete que algún día reemplazará el paquete stdlib re).

Parece tener (entre otras cosas) más posibilidades con respecto a Unicode. Por ejemplo, es compatible con \X, que se usa para hacer coincidir un solo grafema (ya sea que combine o no). También es compatible con la coincidencia en propiedades, bloques y scripts unicode, por lo que puede usar \p{M} para referirse a las marcas de combinación. El \X mencionado anteriormente es equivalente a \P{M}\p{M}* (un carácter que NO es una marca de combinación, seguido de cero o más marcas de combinación).

Tenga en cuenta que esto hace \X más o menos el equivalente de Unicode ., no de \w, por lo que en su caso, \w\p{M}* es lo que necesita.

Es (por ahora) un paquete que no es stdlib, y no sé qué tan preparado está (y no viene en una distribución binaria), pero es posible que desee probarlo, ya que parece ser la respuesta más fácil/más "correcta" a su pregunta. (De lo contrario, creo que desciende a los rangos de caracteres explícitamente, como se describe en mi comentario a la respuesta anterior).

Consulte también this page con información sobre expresiones regulares de Unicode, que también puede contener información útil para usted (y puede servir como documentación para algunos de los aspectos implementados en el paquete de expresiones regulares).

1

Puede usar unicodedata.normalize para componer la combinación de signos diacríticos en un carácter 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> 

Sé que dijiste que no desea normalizar, pero no creo que haya un problema con esta solución, ya que sólo se está normalizando la cadena va a contrastar, y no tienen para cambiar el nombre del archivo en sí o algo así.

+1

Sí, eso me dirá si tengo una coincidencia, pero después de hacer la coincidencia, saco grupos coincidentes y luego hago cosas con ellos. Si utilicé su enfoque, entonces los bytes que tengo después no serían los mismos bytes que están en el nombre de archivo – Rory

+0

que veo. ¿Sabes si las cadenas son consistentes en el uso de la combinación de signos diacríticos (siempre combinando, o al menos siempre combinando o no dentro de una sola cadena)? De ser así, podría normalizar los resultados a NFC o NFD nuevamente según sea necesario. De lo contrario, creo que tendrás que recurrir a trucos para detectar la posición de combinar signos diacríticos en la cadena original e intentar usar esa información para descomponer solo los caracteres necesarios (lo que sería más trabajo que descomponer todo o De ningún modo). – Steven

+0

O tal vez simplemente cambie la expresión y use los rangos para los signos diacríticos de combinación que le interesan, y use algo como \ w [\ u0300- \ u036F]? en lugar de simplemente \ w – Steven

Cuestiones relacionadas