使用UTF-8字符串而非Unicode进行正则表达式有什么优缺点?

0 投票
2 回答
1332 浏览
提问于 2025-04-15 14:36

通常,在使用国际语言时,Python的最佳实践是使用unicode,并且尽早将任何输入转换为unicode,最后再转换为字符串编码(大多数情况下是UTF-8)。

但是,当我需要在unicode上使用正则表达式时,发现这个过程并不是很友好。比如说,如果我想找到字符'é'后面跟着一个或多个空格,我必须这样写(注意:我的命令行或Python文件设置为UTF-8):

re.match('(?u)\xe9\s+', unicode)

所以我必须写出'é'的unicode代码。这并不是很方便,如果我需要从一个变量构建正则表达式,事情就变得复杂了。举个例子:

word_to_match = 'Élisa™'.decode('utf-8') # that return a unicode object
regex = '(?u)%s\s+' % word_to_match
re.match(regex, unicode)

这只是一个简单的例子。如果你有很多正则表达式需要一个接一个地处理,而且里面有特殊字符,我发现直接在UTF-8编码的字符串上做正则表达式更简单、更自然。比如:

re.match('Élisa\s+', string)
re.match('Geneviève\s+', string)
re.match('DrØshtit\s+', string)

我是不是漏掉了什么?使用UTF-8的方法有什么缺点吗?

更新

好的,我找到问题了。我在ipython中做测试,但不幸的是,它似乎搞乱了编码。举个例子:

在Python命令行中

>>> string_utf8 = 'Test « with theses » quotes Éléments'
>>> string_utf8
'Test \xc2\xab with theses \xc2\xbb quotes \xc3\x89l\xc3\xa9ments'
>>> print string_utf8
Test « with theses » quotes Éléments
>>>
>>> unicode_string = u'Test « with theses » quotes Éléments'
>>> unicode_string
u'Test \xab with theses \xbb quotes \xc9l\xe9ments'
>>> print unicode_string
Test « with theses » quotes Éléments
>>>
>>> unicode_decoded_from_utf8 = string_utf8.decode('utf-8')
>>> unicode_decoded_from_utf8
u'Test \xab with theses \xbb quotes \xc9l\xe9ments'
>>> print unicode_decoded_from_utf8
Test « with theses » quotes Éléments

在ipython中

In [1]: string_utf8 = 'Test « with theses » quotes Éléments'

In [2]: string_utf8
Out[2]: 'Test \xc2\xab with theses \xc2\xbb quotes \xc3\x89l\xc3\xa9ments'

In [3]: print string_utf8
Test « with theses » quotes Éléments

In [4]: unicode_string = u'Test « with theses » quotes Éléments'

In [5]: unicode_string
Out[5]: u'Test \xc2\xab with theses \xc2\xbb quotes \xc3\x89l\xc3\xa9ments'

In [6]: print unicode_string
Test « with theses » quotes Ãléments

In [7]: unicode_decoded_from_utf8 = string_utf8.decode('utf-8')

In [8]: unicode_decoded_from_utf8
Out[8]: u'Test \xab with theses \xbb quotes \xc9l\xe9ments'

In [9]: print unicode_decoded_from_utf8
Test « with theses » quotes Éléments

如你所见,ipython在使用u''表示法时搞乱了编码。这就是我遇到问题的原因。这个bug在这里提到过:https://bugs.launchpad.net/ipython/+bug/339642

2 个回答

3

如果你在Python代码中使用utf-8编码,你可以直接写:

u'Élisa'

这样就会得到一个unicode字符串,相当于写:

u'\xc9lisa'

所以加上'u'这个前缀,就不需要再进行解码了。如果你不加'u',直接写:

'Élisa'

那么你得到的就是一个(utf-8编码的)字节串,相当于:

'\xc3\x89lisa'
3

你在用 Python 2.x 吗?如果是的话,通常来说,把非 ASCII 字符放在字节字符串里是不太好的做法。最好从头到尾都使用 Unicode 字符串:

re.match(u'Élisa™\\s+', unicodestring)

在字符串前面加个‘u’看起来可能有点奇怪,但在 Python 3.x 里就没有这个了,其实也没那么糟糕。

用正则表达式匹配 UTF-8 字符串只适用于一小部分情况。如果你想要不区分大小写的匹配,或者在 [group] 里使用非 ASCII 字符,或者需要根据长度来匹配,那就会出错。最好还是用 Unicode。

如果你只用 \s,可能不太需要 (?u),因为它只会引入一些比较特殊的空格,而这些空格你可能不想匹配。不过,对于 Unicode 字符串的不区分大小写匹配来说,这个是有用的。

撰写回答