Unicode, expresiones regulares y PyPy.

Escribí un progtwig para agregar (limitado) compatibilidad con Unicode a las expresiones regulares de Python, y aunque está funcionando bien en CPython 2.5.2, no está funcionando en PyPy ( 1.5.0-alpha0 1.8.0, implementando Python 2.7.1 2.7.2). ambos ejecutándose en Windows XP ( Edición: como se ve en los comentarios, @dbaupp podría ejecutarse bien en Linux). No tengo idea de por qué, pero sospecho que tiene algo que ver con mis usos de u" y ur" . La fuente completa está aquí , y los bits relevantes son:

 # -*- coding:utf-8 -*- import re # Regexps to match characters in the BMP according to their Unicode category. # Extracted from Unicode specification, version 5.0.0, source: # http://unicode.org/versions/Unicode5.0.0/ unicode_categories = { ur'Pi':ur'[\u00ab\u2018\u201b\u201c\u201f\u2039\u2e02\u2e04\u2e09\u2e0c\u2e1c]', ur'Sk':ur'[\u005e\u0060\u00a8\u00af\u00b4\u00b8\u02c2-\u02c5\u02d2-\u02df\u02...', ur'Sm':ur'[\u002b\u003c-\u003e\u007c\u007e\u00ac\u00b1\u00d7\u00f7\u03f6\u204...', ... ur'Pf':ur'[\u00bb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d\u2e1d]', ur'Me':ur'[\u0488\u0489\u06de\u20dd-\u20e0\u20e2-\u20e4]', ur'Mc':ur'[\u0903\u093e-\u0940\u0949-\u094c\u0982\u0983\u09be-\u09c0\u09c7\u0...', } def hack_regexp(regexp_string): for (k,v) in unicode_categories.items(): regexp_string = regexp_string.replace((ur'\p{%s}' % k),v) return regexp_string def regex(regexp_string,flags=0): """Shortcut for re.compile that also translates and add the UNICODE flag Example usage: >>> from unicode_hack import regex >>> result = regex(ur'^\p{Ll}\p{L}*').match(u'áÇñ123') >>> print result.group(0) áÇñ >>> """ return re.compile(hack_regexp(regexp_string), flags | re.UNICODE) 

(en PyPy no hay coincidencia en el “Ejemplo de uso”, por lo que el result es None )

Reiterando, el progtwig funciona bien (en CPython): los datos de Unicode parecen correctos, el reemplazo funciona según lo previsto, el ejemplo de uso se ejecuta bien (tanto a través de doctest como directamente escribiéndolo en la línea de comandos). La encoding del archivo fuente también es correcta, y Python parece reconocer la directiva de coding en el encabezado.

¿Alguna idea de lo que PyPy hace “diferente” que está rompiendo mi código? Se me ocurrieron muchas cosas (encabezado de coding no reconocido, diferentes codificaciones en la línea de comandos, diferentes interpretaciones de r y u ), pero en lo que respecta a mis pruebas, CPython y PyPy parecen comportarse de manera idéntica, así que no tengo ni idea de qué hacer. intente siguiente

¿Por qué no estás simplemente usando el súper recomendado módulo de regexp Matthew Barnett ?

Funciona tanto en Python 3 como en Python 2 heredado, es un reemplazo directo para re , maneja todas las cosas de Unicode que podrías desear, y mucho más.

Parece que PyPy tiene algunos problemas de encoding, tanto al leer un archivo de origen (quizás un encabezado de coding no reconocido) como al ingresar / emitir en la línea de comandos. Reemplacé mi código de ejemplo con lo siguiente:

 >>> from unicode_hack import regex >>> result = regex(ur'^\p{Ll}\p{L}*').match(u'áÇñ123') >>> print result.group(0) == u'áÇñ' True >>> 

Y siguió trabajando en CPython y fallando en PyPy. Reemplazando el “áÇñ” por sus caracteres escapados – u'\xe1\xc7\xf1' – OTOH hizo el truco:

 >>> from unicode_hack import regex >>> result = regex(ur'^\p{Ll}\p{L}*').match(u'\xe1\xc7\xf1123') >>> print result.group(0) == u'\xe1\xc7\xf1' True >>> 

Eso funcionó bien en ambos. Creo que el problema está restringido a estos dos escenarios (carga de origen y línea de comando), ya que intentar abrir un archivo UTF-8 usando codecs.open funciona bien. Cuando trato de ingresar la cadena “áÇñ” en la línea de comandos, o cuando cargo el código fuente de “unicode_hack.py” usando codecs , obtengo el mismo resultado en CPython:

 >>> u'áÇñ' u'\xe1\xc7\xf1' >>> import codecs >>> codecs.open('unicode_hack.py','r','utf8').read()[19171:19174] u'\xe1\xc7\xf1' 

Pero diferentes resultados en PyPy:

 >>>> u'áÇñ' u'\xa0\u20ac\xa4' >>>> import codecs >>>> codecs.open('unicode_hack.py','r','utf8').read()[19171:19174] u'\xe1\xc7\xf1' 

Actualización: Issue1139 enviado en el sistema de seguimiento de errores de PyPy, veamos cómo resulta …