将Unicode字符串拆分为单词

9

我正在尝试将Unicode字符串(简化版)拆分成单词,就像这样:

print re.findall(r'(?u)\w+', "раз два три")

我希望看到的是:

['раз','два','три']

但我实际得到的是:
['\xd1', '\xd0', '\xd0', '\xd0', '\xd0\xb2\xd0', '\xd1', '\xd1', '\xd0']

我做错了什么?

编辑:

如果在字符串前面使用u

print re.findall(r'(?u)\w+', u"раз два три")

I get:

[u'\u0440\u0430\u0437', u'\u0434\u0432\u0430', u'\u0442\u0440\u0438']

编辑 2:

看起来我应该先阅读文档:

 print re.findall(r'(?u)\w+', u"раз два три")[0].encode('utf-8')

会给我:

раз

只是为了确保,那么这听起来像是一个适当的方法吗?

在提取所有\w+字符串和在\s+上分割之间有所不同。显然,你希望在这两种情况下都启用(?u)。在打印之前不要进行手动编码。打印到字符流中,它将具有编码,而不是字节流,它没有。在Python中使用Matthew Barnett的正则表达式库进行Unicode正则表达式。不要使用re:它不能正常工作。 - tchrist
1个回答

6

您实际上是在Unicode方案中得到了您所期望的内容。您认为没有得到内容是因为字符串进行了奇怪的转义,这是因为您正在查看字符串的 reprs ,而不是打印它们的未转义值。(这只是列表显示的方式。)

>>> words = [u'\u0440\u0430\u0437', u'\u0434\u0432\u0430', u'\u0442\u0440\u0438'] 
>>> for w in words:
...     print w # This uses the terminal encoding -- _only_ utilize interactively
... 
раз
два
три
>>> u'раз' == u'\u0440\u0430\u0437'
True

不要错过我的有关打印这些Unicode字符串的评论。通常,如果您要将它们发送到屏幕、文件、通过线路等,您需要手动将它们编码为正确的编码方式。当您使用print时,Python会尝试利用您终端的编码方式进行输出,但只能在有终端的情况下才能这样做。因为通常您不能确定是否有终端,所以您应该仅在交互式解释器中依赖此功能,并始终显式地编码到正确的编码方式。
在这种简单的基于空格分隔的方法中,您可能根本不想使用正则表达式,而只需要使用unicode.split方法。
>>> u"раз два три".split()
[u'\u0440\u0430\u0437', u'\u0434\u0432\u0430', u'\u0442\u0440\u0438']

您提供的顶部(bytestring)示例无法正常工作,因为re基本上假定其语义中所有的bytestrings都是ASCII,但您的不是。使用Unicode字符串可以使您获得正确的字母表和区域设置语义。尽可能地,文本数据应始终使用unicode而不是str来表示。


不,我不认为你应该手动编码。你应该在输出上设置编码。如果你使用Matthew Barnett的regex replacement library替换re,那么很多Unicode问题就会消失。如果你在Python3的宽版本上使用regex,你的Unicode问题会得到很大改善。违反这三个要求中的任何一个,你都会受到影响;违反多个要求,你会受到更多的影响。 - tchrist
@tchrist,不,你应该始终明确地处理编码和解码,而不是依赖隐式编码,就像示例所做的那样(除了 Python 2 交互式 print 这个非常狭窄的情况)。我是指您应该在高级代码中反复调用 encodedecode - Mike Graham
1
在Python 2中使用codecs.open返回的类似文件对象,在Python 3中使用非'b' open或许许多多其他封装编码的模块,例如jsonsqlite模块,都是同样明确的。我的意思并不是你应该一直调用str.decode/unicode.encode(Python 3中为bytes.decode/str.encode),而是你不应该依赖隐式编码。 - Mike Graham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接