Python2和Python3正则匹配中文时的编码问题

2021-02-26 14:50:58 浏览数 (1)

我们都会遇到这样的人,他们说话时是中文英文穿插使用的。也就是一句话中有中文也有英文,很多时候没有办法避免,尤其是说一些专业术语时,当然也有纯个人说话习惯和故意的。

我想表达的是,在程序中也难免会遇到这种情况,同一条数据中即有中文也有英文,还可能有数字或其他的字符。如果我们只想要提取出其中的中文内容,把其他的“杂质”过滤掉,我们可以使用正则来实现这个功能。

但是,在使用中,也会有一些问题困扰我们,比如对于Python2和Python3来说,就会有一些区别需要注意。我们现在就来看怎么进行处理。

一、Python3中正则匹配中文

Python中的正则匹配是通过一套字符规则来进行匹配的,通过re模块来实现。

参考:Python 正则表达式re模块的使用

Windows系统中,re中的w可以匹配大小写英文字母、数字和中文。Linux系统中,w不能匹配中文。

代码语言:javascript复制
# coding=utf-8
import re
 
 
test_str = 'When面对困难111,we正面面对,yes,加油!666'
comp = re.match(r'w ', test_str)
print(comp.group())

运行结果:

代码语言:javascript复制
# Windows运行结果
When面对困难111
# Linux运行结果
When

但是,这样的结果并不是我们需要的,我们只要中文,因此不能使用w来匹配。

我们可以通过在中括号[]内指定字符范围来匹配中文,中文的字符范围是 u4E00-u9FA5 。

代码语言:javascript复制
# 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)

运行结果:

代码语言:javascript复制
['面对困难', '正面面对', '加油']

可以看到,我们成功匹配到了test_str中的所有中文。

二、Python2中匹配中文的问题

在实际工作中,还有非常多的生产环境在使用Python2,如果公司既有Python2也有Python3的环境,那么,我们的代码部署之后就有可能在Python2和Python3两种解释器上运行。

我们看一下上面的代码在Python2中的运行结果。

代码语言:javascript复制
['When', '111', 'e', 'es', '666']

上面在Python3中匹配中文的代码没有做任何改动,在Python2中运行时,匹配结果跟我们的需求完全背道而驰。

那是什么原因造成的呢?其实是Python2解释器和Python3解释器编码不同造成的。Python2和Python3最大的区别,或者说最让程序员头疼的问题基本都是编码问题,不过在这里不做过多讨论。

如何可以证明是编码问题呢?我们可以在test_str前和 '[u4E00-u9FA5] ' 前加一个 u ,看看结果会怎样。

代码语言:javascript复制
# coding=utf-8
import re
 
 
test_str = u'When面对困难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)

运行结果:

代码语言:javascript复制
[u'u9762u5bf9u56f0u96be', u'u6b63u9762u9762u5bf9', u'u52a0u6cb9']
面对困难
正面面对
加油

可以看到,现在我们匹配到的结果,已经不是上面与需求背道而驰的结果了。虽然是我们看不懂的Unicode编码字符,但是,最起码匹配到的内容是正确的,我们做一下解码就可以了。

注意:python中的print关键字是做“字符串格式化输出",它本身就会自动对我们得到的结果做处理,比如上面的结果我们不自己解码,print也会帮我们解码。

三、Python2中正确匹配中文

在上面的代码中,我们在字符串的前面加了一个 u ,表示字符串是Unicode编码的字符串,这样就完成了匹配中文的功能。

但是,在实际中,这样去拼接并不是一个优雅的方法(即使通过代码拼接)。

我们应该将字符串进行编码,编码之后的字符串就是Unicode字符串了(使用decode()或使用unicode())。

代码语言:javascript复制
# 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)

运行结果:

代码语言:javascript复制
[u'u9762u5bf9u56f0u96be', u'u6b63u9762u9762u5bf9', u'u52a0u6cb9']
面对困难
正面面对
加油

注意:在编码的时候,应该使用utf-8,在解码的时候应该使用gbk,否则会乱码。

四、Python3和Python2兼容

上面我们分别完成了在Python3和Python2中匹配中文,这两种方式在Windows和Linux上的运行结果是一样的,所以说我们不用担心跨平台的问题,不管服务器是什么操作系统都可以兼容。

但是这两种方式都不能同时兼容Python3和Python2,如果要让我们的代码能够同时在两个版本的解释器中运行,只能通过分支判断的方式来实现了。

Python中可以使用sys.version来获取当前解释器的版本,我们这里可以通过版本来判断。下面是完整代码。

代码语言:javascript复制
# 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)

运行结果:

代码语言:javascript复制
# Python3
['面对困难', '正面面对', '加油']
面对困难
正面面对
加油
 
# Python2
['xc3xe6xb6xd4xc0xa7xc4xd1', 'xd5xfdxc3xe6xc3xe6xb6xd4', 'xbcxd3xd3xcd']
面对困难
正面面对
加油

现在我们可以同时在Python3和Python2中匹配中文了。

但是,在Python2中,当我们直接打印匹配结果的列表时,显示的并不是中文,遍历出来打印才显示中文。

这个问题在Python2中是避免不了的,如果我们要将结果打印成一个列表且显示中文的效果,可以用以下两种方式来实现。但是打印的数据类型已经转换成字符串了,不再是列表,只是数据的样子是列表的样子而已。

代码语言:javascript复制
# 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))

运行结果:

代码语言:javascript复制
["面对困难", "正面面对", "加油"]
<type 'str'>

0 人点赞