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

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

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

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

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

一、Python3中正则匹配中文

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

参考: https://blog.csdn.net/weixin_43790276/article/details/90690569

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 = 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)

运行结果:

[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'>

 

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小斌哥ge

非常感谢,祝你一切顺利。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值