为 Python2 和 Python3 编写 unicode 正则表达式

alv*_*vas 5 python regex unicode python-2.7 python-3.x

我可以使用Python2 中的ur'something're.U标志来编译正则表达式模式,例如:

$ python2
Python 2.7.13 (default, Dec 18 2016, 07:03:39) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> pattern = re.compile(ur'(«)', re.U)
>>> s = u'«abc «def«'
>>> re.sub(pattern, r' \1 ', s)
u' \xab abc  \xab def \xab '
>>> print re.sub(pattern, r' \1 ', s)
 « abc  « def « 
Run Code Online (Sandbox Code Playgroud)

在 Python3 中,我可以避免u'something'甚至re.U标志:

$ python3
Python 3.5.2 (default, Oct 11 2016, 04:59:56) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> pattern = re.compile(r'(«)')
>>> s = u'«abc «def«'
>>> print( re.sub(pattern, r' \1 ', s))
 « abc  « def « 
Run Code Online (Sandbox Code Playgroud)

但目标是编写正则表达式,使其同时支持 Python2 和 Python3。而这样做ur'something'的Python3将导致语法错误:

>>> pattern = re.compile(ur'(«)', re.U)
  File "<stdin>", line 1
    pattern = re.compile(ur'(«)', re.U)
                               ^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

由于这是一个语法错误,即使在声明模式之前检查版本在 Python3 中也不起作用:

>>> import sys
>>> _pattern = r'(«)' if sys.version_info[0] == 3 else ur'(«)'
  File "<stdin>", line 1
    _pattern = r'(«)' if sys.version_info[0] == 3 else ur'(«)'
                                                             ^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

如何对正则表达式进行 unicode 以同时支持 Python2 和 Python3?


尽管在这种情况下r' '可以u' '通过删除文字字符串轻松替换。

有一些复杂的正则表达式需要r' '出于理智的考虑,例如

re.sub(re.compile(r'([^\.])(\.)([\]\)}>"\'»]*)\s*$', re.U), r'\1 \2\3 ', s)
Run Code Online (Sandbox Code Playgroud)

所以解决方案应该包括文字字符串的r' '使用,除非有其他方法可以解决它。但请注意,使用字符串字面量或unicode_literals或 from__future__是不可取的,因为它会导致大量其他问题,尤其是。在我使用的代码库的其他部分,请参阅http://python-future.org/unicode_literals.html

出于特定原因,代码库不鼓励 unicode_literals 导入但使用r' '符号是因为填充它并对其中的每一个进行更改将非常痛苦,例如

cco*_*cco 1

你真的需要原始字符串吗?对于您的示例,需要 unicode 字符串,但不需要原始字符串。原始字符串很方便,但不是必需的 - 只需将\\原始字符串中使用的任何字符串加倍并使用纯 unicode 即可。

\n\n

Python 2 允许将原始字符串与 unicode 字符串连接(生成 unicode 字符串),因此您可以使用r\'([^\\.])(\\.)([\\]\\)}>"\\\'\' u\'\xc2\xbb\' r\']*)\\s*$\'
\n在 Python 3 中,它们都将是 unicode,因此这也可以工作。

\n