小马哥正在针对Python的所有常见知识进行汇总,更会有大量实战项目不断补充进来.
点击-->全栈工程师养成---Python内容导航页<--查看所有Python内容
小马哥在使用正则表达式面对转义字符的时候,发现字符串的转义与正则的转义有冲突的情况,总一些虽说不难,但是让人感觉没规律的地方,于是就专门研究了一下,首先捋一下知识点,约定一个前提概念:
字符中的转义: 属于字符串的概念,作用于打印. 例如,要完成一个退格,一个制表符,一个换行,这个用字符串如何表示?
简单,"\b,\t,\n",不过是用"\"来转义一下普通字符嘛,
是的,因为b,t,n是普通字符,如果直接输出,当然就是字符,于是加上"\",
打印的时候就是另一种意思了,这个打印,可以是输出到屏幕,也可以是其它输出
正则表达式中的转义: 看到这里,你会想起,正则里面好像也有转义的概念,例如,"."代表匹配字符串里面的任意字符(换行符除外),如果需要匹配真正的"."这个字符怎么办?于是我们用转义字符"."就代表匹配字符串中的"."了.
你有没有想过这个问题,字符串中的转义和正则中的转义不是一套概念体系,如果两者没有表达上的冲突,那么相安无事,可是状况恰恰是有冲突的,"\b"在字符串中表示转义后的结果: 退格;而在正则中代表匹配目标字符串的边界. 于是就要想办法解决冲突: 定义了原始字符串来屏蔽掉冲突.
只看说明,你还是一头蒙的,那么看例子来阐述一遍上面所有的问题:
首先,字符串的转义
# 字符串中的转义: 斜杠\代表转义字符,\b代表转义之后的字符串,是退格
data = '123\b456'
# 显示一下结果
print(data) #发现被转义后: 12456
data = '123\n456'
print(data) #换行: 就是通过转义符把n进行转义表示回车
123456
123
456
如上还有\t制表符也是同样的意思,这些,都是来自于ASCII对字符的规定,记住: 这些属于字符串中的转义
然后,正则的转义
import re
print('第一次试验')
data = 'hello1 python,hello2 java'
pattern = '\bhello.'
result = re.findall(pattern,data)
print(result)
'''
分析:
这个时候的正则表达式模式,没有匹配到期望的hello1与hello2,因为\b这里代表的不是正则的边界
1,pattern = '\bhello.',首先是一个字符串,就要接受字符串的处理,
根据ASCII表,\b是退格,是一个看不到的字符,所以'\b'是一个字符,hello是另外的字符,
2,我们期望的正则模式是: '边界hello.',这个"边界"的表示方法和字符的ASCII码冲突,没有体现出来
于是,清楚了原因,我们应该设计一个模式,在经历字符串ASCII解析后,再传递给正则引擎之后是\bhello
应该这样写: '\\bhello'
'''
print('第二次试验')
data = 'hello1 python,hello2 java'
pattern = '\\bhello.' #这时,经过字符的ASCII表解析后,得到的字符串是'\bhello'
result = re.findall(pattern,data)
print(result)
'''
到此,你心里应该有了一个: 计算机内部针对 字符 - ->模式 的过程
不是你写了一个字符串,它就是正则的模式了,而是计算机内部要根据ASCII码进行了解析,解析的结果,拿给了正则引擎去用来搜索目标文本,
而ASCII码解析后的结果,和你期望的正则的模式发生变化了,所以正则表达式解析来的结果,不如我们期望的
'''
第一次试验
[]
第二次试验
['hello1', 'hello2']
如果通过上面的例子,你懂了ASCII码在暗中干了一件'见不得人'的事,如果你的脑力还够用,那么咱们再来看一个它的更有意思的事情
需求: 'python\java\go\c',解析出里面的" \ ",在字符概念领域,它是转义字符,在正则领域,它也是转义字符,如何操作呢?
上面,我们主要目的:让你知道,ASCII码和正则,针对转义是不同的,有冲突的,例如,\b在两者概念体系中就冲突了,
import re
data = 'python\java\go\c'
'''
pattern1
这个都不用试验,肯定是错的,语法错误,解析都通不过,相当于,你想打印" ' "单引号,但是字符串的定义就是用单引号或者双引号来表示
\'相当于失去了字符串"'"的定义作用,而把"'"看做普通字符,那么这样,字符串的pattern1,就没有了字符串的结尾符了,必然错误
'''
# pattern1 = '\' #必须注释了,语法都通不过检查
'''
pattern2
用上一个例子中分析的结果,我们用转义字符把斜杠处理过,得到就是ASCII处理后的"\",再拿去交给正则引擎,这个时候正则我们应该没问题了
的确,这里经过ASCII码处理,最终交给正则的是"\",这个时候就该正则引擎起作用了,对于它"\"也是一个转义符,可只要\这是一个不完整的转义
于是抛出error: bad escape (end of pattern) at position 0
'''
try:
pattern2 = '\\'
print(pattern2)
result2 = re.findall(pattern2,data)
print(result2)
except Exception as e:
print("Error: ",e)
'''
pattern3
我们应该传递给正则解析引擎一个"\\",经过正则处理,它会得到"\"这个仅仅代表字符的模式,拿着去和目标文本比对,搜索目标"\"
'\\\\'经过ASCII码处理,得到"\\",正则引擎处理'\\',得到'\'
'''
pattern3 = '\\\\'
result3 = re.findall(pattern3,data)
print(result3)
\
Error: bad escape (end of pattern) at position 0
['\\', '\\', '\\']
总结上面两个例子
例一,你应该明白了,一个字符串能作为正则的模式,中间是经过ASCII码转换的,但是为什么"\d","\w"等就相安无事呢?因为ASCII码没"整"它们;
例二,对于""这种比较特殊的东东,经过ASCII和正则的两次转义,语法都要正确,才能去匹配目标文本中的目标字符
有没有一种方式,不用这么麻烦,于是出现了原始字符串.
原始字符串的用法:解除字符与正则关于转义的冲突
import re
data = 'python\java\go\c'
pattern = r'\\' #这里为什么还要是两个斜杠呢? 毕竟这里是字符串的定义
print(pattern)
result = re.findall(pattern,data)
print(result)
data = 'hello1 java,hello2 python'
pattern = r'\bhello.' #这里就去掉了\b的退格作用
print(pattern)
result = re.findall(pattern,data)
print(result)
\\
['\\', '\\', '\\']
\bhello.
['hello1', 'hello2']
可能有的同学有疑问: 为什么上面打印的result关于findall结果的地方,result列表里面都是'\',其实'\'代表的是一个字符'\',print()打印这个动作就变成''了.不信去试试.
小马哥正在针对Python的所有常见知识进行汇总,更会有大量实战项目不断补充进来.
点击-->全栈工程师养成---Python内容导航页<--查看所有Python内容