2012-05-06 11 views
7

Escribí un programa para agregar (limitado) unicode support a las expresiones regulares de Python, y aunque funciona bien en CPython 2.5.2 no funciona en PyPy ( 1.5.0-alpha0 1.8.0, la implementación de Python 2.7.1 2.7.2), ambos se ejecutan en Windows XP (Editar: como se ve en los comentarios, @dbaupp podría ejecutarlo 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 completo es here, y los bits relevantes son:Unicode, expresiones regulares y PyPy

# -*- 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 ninguna coincidencia en el "Ejemplo de uso", por lo result es None)

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

¿Alguna idea de lo que PyPy hace "diferente" que está rompiendo mi código? Muchas cosas vinieron a mi cabeza (encabezado 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, tanto CPython como PyPy parecen comportarse de forma idéntica, así que no tengo ni idea de qué prueba a continuación.

+1

¿Hay alguna razón en particular por la que está utilizando una versión tan inestable de PyPy? (La última versión estable es 1.8.) – huon

+1

Además, el ejemplo dado funciona bien para mí usando '[PyPy 1.8.0 con GCC 4.4.3] en linux2'. Por lo tanto, parece que lo que debe probar a continuación es actualizar su PyPy. – huon

+0

@dbaupp uh ...porque eso es lo que está instalado en mi máquina? (hey, era nuevo cuando lo instalé ...) Ahora, en serio, acabo de actualizarlo a 1.8.0 y aún obtengo los mismos resultados. Como logró hacer que funcione en Linux, tal vez el problema esté restringido a Windows. Investigaré más a fondo. – mgibsonbr

Respuesta

6

Parece que PyPy tiene algunos problemas de codificación, tanto al leer un archivo fuente (cabecera no reconocida coding, tal vez) como al ingresar/dar salida en la línea de comando. He reemplazado mi código de ejemplo, con la 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. Sustitución de la "ACN" por sus caracteres de escape - 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 fuente y línea de comando), ya que intentar abrir un archivo UTF-8 usando codecs.open funciona bien. Cuando trato de entrada de la cadena "ACN" en la línea de comandos, o cuando me carga el código fuente de "unicode_hack.py" usando codecs, me sale 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 con 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 presentado el sistema de seguimiento de fallos PyPy, vamos a ver cómo esto resulta ...

7

¿por qué no simplemente utilizando Matthew Barnett’s super-recommended regexp module en cambio?

Funciona tanto con Python 3 como con Python 2 heredado, es un reemplazo directo para re, maneja todas las cosas Unicode que pueda desear, y mucho más.

+0

Claro, consideré usar otros motores regex (como Ponyguruma por ejemplo), al final puedo ir con su sugerencia, ¡gracias! Pero el problema aquí no fue sobre expresiones regulares, sino soporte unicode en PyPy en Windows (por supuesto, cuando hice la pregunta no sabía de qué se trataba, por lo que era posible un problema con expresiones regulares). Por cierto, acabo de ver que el [informe de error] (https://bugs.pypy.org/issue1139) ha sido confirmado. – mgibsonbr

Cuestiones relacionadas