2012-05-06 26 views
7

Ich schrieb ein Programm, um (begrenzt) unicode support zu Python Regexes hinzuzufügen, und während es auf CPython 2.5.2 funktioniert, funktioniert es nicht auf PyPy ( 1.5.0-alpha0 1.8.0, Implementierung von Python 2.7.1 2.7.2), beide unter Windows XP (Edit: wie in den Kommentaren gesehen, @dbaupp könnte es gut laufen auf Linux). Ich habe keine Ahnung warum, aber ich vermute, dass es etwas mit meinen Anwendungen von u" und ur" zu tun hat. Die vollständige Quelle ist here, und die entsprechenden Bits sind:Unicode, reguläre Ausdrücke und 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) 

(auf PyPy gibt es keine Übereinstimmung in der "Anwendungsbeispiel", so result ist None)

erneuten Ausdruck, arbeitet das Programm fein (auf CPython): Die Unicode-Daten scheinen korrekt zu sein, die Ersetzung funktioniert wie vorgesehen, das Anwendungsbeispiel läuft ok (beide über doctest und direkt in der Befehlszeile eingeben). Die Codierung der Quelldatei ist ebenfalls korrekt, und die Direktive coding in der Kopfzeile scheint von Python erkannt worden zu sein.

Irgendwelche Ideen, was PyPy "anders" macht, das meinen Code bricht? Viele Dinge kamen zu meinem Kopf (unerkannt coding Header, verschiedene Codierungen in der Befehlszeile, verschiedene Interpretationen von r und u) aber soweit meine Tests gehen, scheint sowohl CPython und PyPy identisch zu verhalten, so dass ich nicht weiß, was zu tun versuche es als nächstes.

+1

Gibt es einen bestimmten Grund, warum Sie eine solche alte instabile Version von PyPy verwenden? (Die letzte stabile Version ist 1.8.) – huon

+1

Auch das angegebene Beispiel funktioniert gut mit '[PyPy 1.8.0 mit GCC 4.4.3] auf linux2'. Es sieht also so aus, als ob du dein PyPy aktualisieren musst. – huon

+0

@ dbaupp uh ...Weil das auf meinem Rechner installiert ist? (hey, es war neu, als ich es installiert habe ...) Nun, im Ernst, ich habe es nur auf 1.8.0 aktualisiert und erhalte immer noch die gleichen Ergebnisse. Da Sie es geschafft haben, es unter Linux arbeiten zu lassen, ist das Problem möglicherweise auf Windows beschränkt. Ich werde weiter untersuchen. – mgibsonbr

Antwort

6

Scheint PyPy hat einige Codierungsprobleme, sowohl beim Lesen einer Quelldatei (nicht erkannte coding Header, vielleicht) und beim Eingeben/Ausgeben in der Befehlszeile. Ich habe meinen Beispielcode durch folgenden Code ersetzt:

Und es arbeitete weiter an CPython und fehlgeschlagen an PyPy. Ersetzen der „Kirche in Not“ für seine maskierten Zeichen - u'\xe1\xc7\xf1' - OTOH hat den Trick:

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

, die auf beide fein gearbeitet. Ich glaube, dass das Problem auf diese beiden Szenarien beschränkt ist (Laden der Quelle und Befehlszeile), da der Versuch, eine UTF-8-Datei mit codecs.open zu öffnen, einwandfrei funktioniert. Als ich nach Eingabe versuchen, die Zeichenfolge „Kirche in Not“ in der Befehlszeile, oder wenn ich den Quellcode von „unicode_hack.py“ lade codecs verwenden, erhalte ich das gleiche Ergebnis auf CPython:

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

aber auf unterschiedliche Ergebnisse PyPy:

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

Update:Issue1139 auf PyPy Bug-Tracking-System vorgelegt, lassen Sie uns sehen, wie das herausstellt ...

7

Warum sind Sie nicht einfachmitstattdessen?

Es funktioniert sowohl auf Python 3 und Legacy Python 2, ist ein Drop-in-Ersatz für re, behandelt alle Unicode-Sachen, die Sie wollen, und eine ganze Menge mehr.

+0

Sicher, ich überlegte mir, andere Regex-Engines zu verwenden (wie Ponyguruma zum Beispiel), ich kann mit deinem Vorschlag am Ende gehen, danke! Es stellte sich jedoch heraus, dass es sich hier nicht um Regexes handelte, sondern um die Unicode-Unterstützung von PyPy unter Windows (wenn ich natürlich die Frage stellte, wusste ich nicht, was es war, also war ein Problem mit Regexen eine Möglichkeit). BTW hat gerade gesehen, dass der [bug report] (https://bugs.pypy.org/issue1139) bestätigt wurde. – mgibsonbr