python-字符串全解(六):正则表达式-转义与非转义

字符串的处理可以说是计算机中世界中用的最多的,最普遍的操作。人机交互,网络数据交换格式(xml,json),业务系统中的姓名,地址,甚至我们的源代码都是字符串。我们之前讲过了字符串的索引,分片以及字符串的相关方法,这些都是针对已知的字符串的操作,假如有大量的未知文本需要你处理,用正则表达式来处理无疑是很有效的方法。

1.正则表达式基础

通过正则表达式,你可以进行文本的查找,提取,替换,以及校验。之前我们也讲到字符串的find方法,也可以查找字符串。但是find方法只能根据确定的字符串值去查找,比如你要查找一个字符串"abc"子串是否在另外一个字符串中,那么直接用find就可以了;但是如果你要找这个字符串中不确定的电话号码,这个靠find就没有办法查找了,这时候正则表达式就派上用场了。对于python来讲,re模块是python的正在表达式模块,这个模块提供能字符串的匹配,查找,替换以及分割。我们先来看一个简单的例子:

python 复制代码
import re
a = "这是一个电话:18612324511,这不是一个电话186111233334"
b = re.findall(r'\b1[3-9]\d{9}\b', a)
print("b = {}".format(b))
# 输出结果:b = ['18612324511']

使用正则模块很简单,直接imoprt re 模块即可,我们用了一个findall函数,这个函数是找出字符串中符合条件的所有子串,结果是一个列表。我们发现结果列表只有一个电话号码,因为第二个的那串数字有12位,不是一个正确的电话号码。findall的第一个参数是正在表达式,第二个参数是一个字符串,我们需要在这个字符串中查找符合正则表达式的字符串子串。当然findall还有别的参数,我们先关注这两个。

我们看一下这个正则表达式字符串,首先是r开头,表示不转义,也就是后面的串就是代表本来的意思。然后第一个是\b,这个是正则表达式一个特殊组合,代表单词边界,什么叫单词呢?单词就是字母,数字,下划线。\b本身不匹配字符,他只是做为一个占位符。千万别把\b当作转义字符啊,\b只是在正在表达式的语境中代表一个单词占位符。

说到这里,你可能有个疑问:正则表达式可以不使用r这种不转义的方式么?答案是当然可以,看下面的代码:

python 复制代码
import re
a = "这是一个电话:18612324511,这不是一个电话186111233334"
b = re.findall('\\b1[3-9]\\d{9}\\b', a)
print("b = {}".format(b))
# 输出结果:b = ['18612324511']

上面的代码唯一的不同之处是去掉了正则表达式前面的r,然后所有的反斜杠\都变成了\\,在字符串中,\是转义的开始,为了表示\本身,所以需要用双反斜杠\\。最终的结果是一样的,但是我们需要多写三个反斜杠,这样反而麻烦,所以一般情况下,只需要在前面写r就可以了。

我们再想一下,如果我们不将反斜杠\换成两个反斜杠\\,会发生什么问题呢?我们再看一下代码:

python 复制代码
import re
a = "这是一个电话:18612324511,这不是一个电话186111233334"
b = re.findall('\b1[3-9]\d{9}\b', a)
print("b = {}".format(b))
# 输出结果:/Users/sunxiaojun/PycharmProjects/pythonProject/main.py:3:
# SyntaxWarning: invalid escape sequence '\d'
#   b = re.findall('\b1[3-9]\d{9}\b', a)
# b = []

我们看到,报了一个警告,提示\d是非法的转义,但是\b没有报,因为\b在转义字符里是退格,所以最后我们看到匹配结果:b = \[\]。

读到这里,我们要明白一个顺序:首先正则表达式是一个字符串,它必须先被python解释之后,然后再给正则模块用,如果\b被python转义是一个退格,那么在内存就是占一个字符的位置,而正则表达式要求的是\b是两个字符,所以就不能被解释为单词边界,只能解释为一个退格,但是在被查找的字符中根本没有退格这个字符,所以结果为空也是理所当然的事情。

为了验证上面的说法,我们看看下面的代码:

python 复制代码
import re
a = "\b"
b = r"\b"
print("a = {}, len(a) = {}, ord(a) = {}, b = {}, len(b) = {}"
      .format(a, len(a), ord(a), b, len(b)))
# 输出结果:a =, len(a) = 1, ord(a) = 8, b = \b, len(b) = 2

我们可以看到a和b长度不同,a是一个字符,b是两个字符。打印出来a看着是空,其实是因为退格是非占位字符。b打印出来就是\b,说明是因为r阻止了转义,从正则表达式的角度看,这个b就代表了字符边界。a只是代表一个退格。ord(a)给出了码点值,是8,因为b是两个字符,所以无法用ord函数。

为了更深刻的理解\b这个字符边界,我们稍稍的再改一下最初的例子,看下面的代码:

python 复制代码
import re
a = "18612324511:这是一个电话,这不是一个电话186111233334"
b = re.findall(r'\b1[3-9]\d{9}\b', a)
print("b = {}".format(b))
# 输出结果:b = ['18612324511']

这个代码的不同之处是,将电话号码移到了最开头,我们仍然能匹配成功。所以\b的作用不仅仅说明当前的字符不是数字,字母,下划线,如果当前是空字符,也可以正确匹配。那如果把电话号码放到字符串末尾呢?我们猜测也应该是正确的,如下面代码所示:

python 复制代码
import re
a = "这不是一个电话186111233334,:这是一个电话:18612324511"
b = re.findall(r'\b1[3-9]\d{9}\b', a)
print("b = {}".format(b))
# 输出结果:b = ['18612324511']

打印出来的结果符合预期。 总结来看:\b匹配字符边界(也就是当前字符必须不是字母,数字和下划线),如果是空(字符串的开头或者结尾),也是可以匹配的。但是\b并不包含在匹配结果里面。

在这个正则表达式中还有其他语法,我们稍后展开,上面列举的代码,我有两个目的:一是看看正则表达式如何和re模块结合使用,二是一定要区分正则表达式中转义和非转义的区别,只有弄明白了这些,你才能正确的写出复杂的正则表达式。

读到了这里,我们做一个总结:首先正则表达式是一个字符串,如果是字符串就要符合python的字符串的规则,比如转义字符,如果你字符串前面没有带r,就需要先转义,然后正则表达式的语法匹配

下一章我们来学习正则表达式详细的语法。

相关推荐
IvanCodes6 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
Patrick在香港7 小时前
Claude 工具调用返回空:8 次失败里只有 1 次状态码不对,其余全带 200
爬虫·python·api·claude·香港
Web3&Basketball8 小时前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
AIFQuant9 小时前
ETF行情API接入踩坑记:从报错到跑通的七个问题
python·金融·区块链·etf·基金
GPU实战笔记10 小时前
云端 Python 开发:JupyterLab 还是 VS Code Remote-SSH?
python·vs code·jupyterlab·remote-ssh·远程开发
狗狗狗狗狗乐啊10 小时前
搭一个 AI 对话工作台 AChat:从 0 到可用的完整记录(一)
python·react.js·ai编程
白猫不黑11 小时前
Python实现简易Web弱口令爆破与防护方案
python·web安全·计算机·网络安全·黑客·信息安全·渗透测试
kuuailetianzi12 小时前
Python初识:定位、优势与发展历程
python
guoran_shini12 小时前
LLM微调-训练垂类问答模型
python·lora·sft