Python2和Python3正则匹配中文时的编码问题
Posted 小斌哥ge
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python2和Python3正则匹配中文时的编码问题相关的知识,希望对你有一定的参考价值。
Python2和Python3正则匹配中文时的编码问题
我们都会遇到这样的人,他们说话时是中文英文穿插使用的。也就是一句话中有中文也有英文,很多时候没有办法避免,尤其是说一些专业术语时,当然也有纯个人说话习惯和故意的。
我想表达的是,在程序中也难免会遇到这种情况,同一条数据中即有中文也有英文,还可能有数字或其他的字符。如果我们只想要提取出其中的中文内容,把其他的“杂质”过滤掉,我们可以使用正则来实现这个功能。
但是,在使用中,也会有一些小问题,比如对于Python2和Python3来说,就会有一些区别需要注意。我们现在就来看怎么进行处理。
一、Python3中正则匹配中文
Python中的正则匹配是通过一套字符规则来进行匹配的,通过re模块来实现。
Windows系统中,re中的\\w可以匹配大小写英文字母、数字和中文。Linux系统中,\\w不能匹配中文。
# coding=utf-8
import re
test_str = When面对困难111,we正面面对,yes,加油!666
comp = re.match(r\\w+, test_str)
print(comp.group())
运行结果:
# Windows运行结果
When面对困难111
# Linux运行结果
When
但是,这样的结果并不是我们需要的,我们只要中文,因此不能使用\\w来匹配。
我们可以通过在中括号[]内指定字符范围来匹配中文,中文的字符范围是 \\u4E00-\\u9FA5 。
# coding=utf-8
import re
test_str = When面对困难111, we 正面面对, yes, 加油!666
comp = re.compile(r[\\u4E00-\\u9FA5]+)
re_result = comp.findall(test_str)
print(re_result)
运行结果:
[面对困难, 正面面对, 加油]
可以看到,我们成功匹配到了test_str中的所有中文。
二、Python2中匹配中文的问题
在实际工作中,还有非常多的生产环境在使用Python2,如果公司既有Python2也有Python3的环境,那么,我们的代码部署之后就有可能在Python2和Python3两种解释器上运行。
我们看一下上面的代码在Python2中的运行结果。
[When, 111, e, es, 666]
上面在Python3中匹配中文的代码没有做任何改动,在Python2中运行时,匹配结果跟我们的需求完全背道而驰。
那是什么原因造成的呢?其实是Python2解释器和Python3解释器编码不同造成的。Python2和Python3最大的区别,或者说最让程序员头疼的问题基本都是编码问题,不过在这里不做过多讨论。
如何可以证明是编码问题呢?我们可以在test_str前和 [\\u4E00-\\u9FA5]+ 前加一个 u ,看看结果会怎样。
# coding=utf-8
import re
test_str = uWhen面对困难111, we 正面面对, yes, 加油!666
comp = re.compile(u[\\u4E00-\\u9FA5]+)
re_result = comp.findall(test_str)
print(re_result)
for s in re_result:
s = s.encode(gbk)
print(s)
运行结果:
[u\\u9762\\u5bf9\\u56f0\\u96be, u\\u6b63\\u9762\\u9762\\u5bf9, u\\u52a0\\u6cb9]
面对困难
正面面对
加油
可以看到,现在我们匹配到的结果,已经不是上面与需求背道而驰的结果了。虽然是我们看不懂的Unicode编码字符,但是,最起码匹配到的内容是正确的,我们做一下解码就可以了。
注意:python中的print关键字是做“字符串格式化输出",它本身就会自动对我们得到的结果做处理,比如上面的结果我们不自己解码,print也会帮我们解码。
三、Python2中正确匹配中文
在上面的代码中,我们在字符串的前面加了一个 u ,表示字符串是Unicode编码的字符串,这样就完成了匹配中文的功能。
但是,在实际中,这样去拼接并不是一个优雅的方法(即使通过代码拼接)。
我们应该将字符串进行编码,编码之后的字符串就是Unicode字符串了(使用decode()或使用unicode())。
# coding=utf-8
import re
test_str = When面对困难111, we 正面面对, yes, 加油!666
comp = re.compile(u[\\u4E00-\\u9FA5]+)
# test_str = unicode(test_str, encoding=utf-8)
# re_result = comp.findall(test_str)
re_result = comp.findall(test_str.decode(utf-8))
print(re_result)
for s in re_result:
s = s.encode(gbk)
print(s)
运行结果:
[u\\u9762\\u5bf9\\u56f0\\u96be, u\\u6b63\\u9762\\u9762\\u5bf9, u\\u52a0\\u6cb9]
面对困难
正面面对
加油
注意:在编码的时候,应该使用utf-8,在解码的时候应该使用gbk,否则会乱码。
四、Python3和Python2兼容
上面我们分别完成了在Python3和Python2中匹配中文,这两种方式在Windows和Linux上的运行结果是一样的,所以说我们不用担心跨平台的问题,不管服务器是什么操作系统都可以兼容。
但是这两种方式都不能同时兼容Python3和Python2,如果要让我们的代码能够同时在两个版本的解释器中运行,只能通过分支判断的方式来实现了。
Python中可以使用sys.version来获取当前解释器的版本,我们这里可以通过版本来判断。下面是完整代码。
# coding=utf-8
import re
import sys
test_str = When面对困难111, we 正面面对, yes, 加油!666
if sys.version[0] == 3:
comp = re.compile(r[\\u4E00-\\u9FA5]+)
re_result = comp.findall(test_str)
else:
comp = re.compile(u"[\\u4E00-\\u9FA5]+")
re_result = comp.findall(test_str.decode(utf-8))
re_result = [s.encode(gbk) for s in re_result]
print(re_result)
for a in re_result:
print(a)
运行结果:
# Python3
[面对困难, 正面面对, 加油]
面对困难
正面面对
加油
# Python2
[\\xc3\\xe6\\xb6\\xd4\\xc0\\xa7\\xc4\\xd1, \\xd5\\xfd\\xc3\\xe6\\xc3\\xe6\\xb6\\xd4, \\xbc\\xd3\\xd3\\xcd]
面对困难
正面面对
加油
现在我们可以同时在Python3和Python2中匹配中文了。
但是,在Python2中,当我们直接打印匹配结果的列表时,显示的并不是中文,遍历出来打印才显示中文。
这个问题在Python2中是避免不了的,如果我们要将结果打印成一个列表且显示中文的效果,可以用以下两种方式来实现。但是打印的数据类型已经转换成字符串了,不再是列表,只是数据的样子是列表的样子而已。
# coding=utf-8
import re
import sys
import json
test_str = When面对困难111, we 正面面对, yes, 加油!666
if sys.version[0] == 3:
comp = re.compile(r[\\u4E00-\\u9FA5]+)
re_result = comp.findall(test_str)
else:
comp = re.compile(u"[\\u4E00-\\u9FA5]+")
re_result = comp.findall(test_str.decode(utf-8))
re_result = [s.encode(gbk) for s in re_result]
# re_result = repr(re_result).decode(string-escape) # 方法一
re_result = json.dumps(re_result, ensure_ascii=False) # 方法二
print(re_result)
print(type(re_result))
运行结果:
["面对困难", "正面面对", "加油"]
<type str>
以上是关于Python2和Python3正则匹配中文时的编码问题的主要内容,如果未能解决你的问题,请参考以下文章