2012-05-06 74 views
7

我編寫了一個程序來向Python正則表達式添加(限制)unicode support,並且它在CPython 2.5.2上工作正常,但它不能在PyPy上工作( 1.5.0-alpha0 1.8.0,實現Python 2.7.1 2.7.2),都在Windows XP上運行(編輯:在評論中看到,@ dbaupp可以在Linux上正常運行)。我不知道爲什麼,但我懷疑這與我使用u"ur"有關。完整的源代碼是here,以及相關的位是:Unicode,正則表達式和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) 

(上PyPy有在「實施例使用」不匹配,因此resultNone

,重申,程序正常工作(上CPython):Unicode數據看起來正確,替換工作按預期運行,使用示例運行正常(均通過doctest並直接在命令行鍵入)。源文件編碼也是正確的,頭文件中的coding指令似乎被Python識別。

PyPy做了什麼「不同」的打破我的代碼的想法?很多東西來到我的頭上(無法識別的coding標題,命令行中的不同解釋,ru的不同解釋),但就我的測試而言,CPython和PyPy似乎行爲相同,所以我對什麼接下來嘗試。

+1

是否有任何特別的原因,你正在使用這樣一箇舊的不穩定版本的PyPy? (最新的穩定版本是1.8。) – huon

+1

此外,給出的例子在linux2上使用'[PyPy 1.8.0 with GCC 4.4.3]「正常工作。所以看起來接下來要嘗試升級你的PyPy。 – huon

+0

@dbaupp呃...因爲這是我的機器上安裝的? (嘿,我安裝它時它是新的......)現在,嚴重的是,我只是將它升級到了1.8.0,並且仍然獲得了相同的結果。既然你設法使它在linux上工作,那麼問題可能只限於Windows。我會進一步調查。 – mgibsonbr

回答

6

似乎PyPy在讀取源文件(無法識別coding標頭,也許)以及在命令行中輸入/輸出時都有一些編碼問題。我用下面的代碼替換了我的示例代碼:

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

而且它一直在使用CPython並在PyPy上失敗。更換「ACN」爲它的轉義字符 - u'\xe1\xc7\xf1' - OTOH的伎倆:

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

這兩個工作的罰款。我相信這個問題僅限於這兩種情況(源代碼加載和命令行),因爲試圖使用codecs.open打開UTF-8文件可以正常工作。當我嘗試輸入命令行字符串「ACN」,或當我加載「unicode_hack.py」使用codecs的源代碼,我得到CPython的相同的結果:

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

但不同的結果上PyPy:

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

更新:提交PyPy bug跟蹤系統Issue1139,讓我們來看看如何原來...

7

你爲什麼不乾脆用而不是3210?

它既適用於Python 3,也適用於傳統Python 2,可以替代re,處理所有需要Unicode的東西,還有更多。

+0

當然,我考慮過使用其他的正則引擎(比如Ponyguruma),最後我會提出你的建議,謝謝!但這裏的問題原來不是正則表達式,而是Windows上PyPy的Unicode支持(當然,當我問這個問題時,我不知道它是什麼,所以正則表達式的問題是可能的)。 BTW剛剛看到[bug報告](https://bugs.pypy.org/issue1139)已被確認。 – mgibsonbr