我编写了一个程序来添加(限制)unicode support到Python正则表达式,虽然它在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,相关的位是:
# -*- 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上“示例用法”中没有匹配,因此result
为None
)
重申,该程序运行正常(在CPython上):Unicode数据似乎正确,替换按预期工作,用法示例运行正常(通过doctest
并直接在命令行中键入)。源文件编码也是正确的,并且标头中的coding
指令似乎被Python识别。
任何关于PyPy做什么“不同”的想法都会破坏我的代码?许多事情发生在我脑海中(无法识别的coding
标题,命令行中的不同编码,对r
和u
的不同解释)但是就我的测试而言,CPython和PyPy似乎都是表现得一样,所以我对接下来要尝试的事情一无所知。
答案 0 :(得分:7)
为什么不是简单地使用Matthew Barnett’s super-recommended regexp
module?
它适用于Python 3和遗留Python 2,是re
的替代品,可以处理您想要的所有Unicode内容,还有更多。
答案 1 :(得分: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上失败了。为其逃脱的角色取代“áÇñ” - 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文件可以正常工作。当我尝试在命令行中输入字符串“áÇñ”时,或者当我使用codecs
加载源代码“unicode_hack.py”时,我在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错误跟踪系统上提交更新: Issue1139,让我们看看结果如何......