第058讲: 论一只爬虫的自我修养6:正则表达式(2) | 学习记录(小甲鱼零基础入门学习Python)

(标答出处: 鱼C论坛)
《零基础入门学习Python》


本节知识点:


上一节课我们通过一个例子(匹配 ip 地址)让大家初步了解到正则表达式的魔力,也让大家充分了解到学习正则表达式是一个相对比较困难的事情。所以这一节课我们将继续学习 正则表达式的语法。

我们依稀还记得在Python中,正则表达式是以字符串的形式来描述的,正则表达式的强大之处在于特殊符号的应用,我们上节课举了例子,例如 点号(.),在正则表达式中表示匹配除了 换行符之外的任何字符,它就是一个特殊的字符。正是这些特殊符号,使得一个正则表达式可以匹配一个复杂的规则,而不仅仅是匹配一个字符串,如果你只需要匹配一个字符串,那用 find() 方法就可以了。

我这里给大家准备了一个列表,Python3 正则表达式特殊符号及用法(详细列表)

这里罗列了python3 所支持的所有正则表达式的特殊符号以及具体的含义,在难以理解的地方,用斜体举了例子给大家看,方便大家理解,大家可以将这个文章收藏起来,以后用到的时候查询就可以了,切记不要死记硬背,因为根本背不住,如果背错了更扎心。

特殊符号是由两部分组成的,一部分是 元字符。(例如我们上节课讲的 点号(.),方括号([]),反斜杠()等)。

所有的元字符包括:. ^ $ * + ? { } [ ] \ | ( )

另一部分就是 反斜杠加上普通符号组成的特殊符号,它拥有特殊的含义。

首先来谈谈元字符

点号(.):是匹配除了换行符之外的任何字符。

| :就相当于逻辑或,学过C语言的同学们都知道,这就是按位或。A|B 表示匹配正则表达式 A或者B

例如:

>>> import re
>>> re.search(r"Python(E|F)", "PythonE")
<_sre.SRE_Match object; span=(0, 7), match='PythonE'>
>>> re.search(r"Python(E|F)", "PythonF")
<_sre.SRE_Match object; span=(0, 7), match='PythonF'>
>>> re.search(r"Python(E|F)", "PythonD")
>>> 

托字符(^):定位匹配,匹配字符串的开始位置(即确定一个位置)。

例如:

>>> re.search(r"^Python", "I love Python")
>>> 
>>> re.search(r"^Python", "Python, I love")
<_sre.SRE_Match object; span=(0, 6), match='Python'>

**美元符号( )**, 匹配输入字符串的结束位置.

>>> re.search(r"Python$", "Python, I love")
>>> 
>>> re.search(r"Python$", "I love Python")
<_sre.SRE_Match object; span=(7, 13), match='Python'>

我们刚刚提到了值组,就是用小括号括起来的,我们上节课也用过了,用小括号括起来跟数学的括号是一样的,把一个东西当做一个整体,那么就把它括起来。

接下来是史上最困难、最复杂的 反斜杠(),反斜杠在正则表达式中应用是最广泛的,它既可以将一个普通的字符变为特殊字符(这部分内容下节课继续讲解),同时也可以解除元字符的特殊功能,这在上节课已经讲过,例如 . 匹配的就不是除换行符之外的任何字符了,他匹配的就是一个点(.)了。

如果在反斜杠后面加的是数字,那么还有两种表示方案:

①如果跟着的数字是 1~99,就表示引用序号对应的值组所匹配的字符串,其中序号所对应的值组:为 \ 前面的值组,\序号必须在对应的值组的正后面,序号为第几个值组。

例如:

>>> re.search(r"(Python)\1", "I love Python")
>>> 
>>> re.search(r"(Python)\1", "I love PythonPython")
<_sre.SRE_Match object; span=(7, 19), match='PythonPython'>

上面的(Python)是第一个值组(序号是从1开始计算的,因为0表示一个八进制数),所以 \1,且**\1** 表示Python,其实 r’(Python)\1’ 就等于 ‘PythonPython’

>>> re.search(r"(love)(Python)\1", "I lovelovePythonPython")  #这样\1 是找不到 (love)的,\序号必须在对应值组的正后方
>>> 
>>> re.search(r"(love)\1(Python)", "I lovelovePythonPython")
<_sre.SRE_Match object; span=(2, 16), match='lovelovePython'>
>>> re.search(r"(love)(Python)\2", "I lovelovePythonPython")
<_sre.SRE_Match object; span=(6, 22), match='lovePythonPython'>
>>> re.search(r"(love)\1(Python)\2", "I lovelovePythonPython")
<_sre.SRE_Match object; span=(2, 22), match='lovelovePythonPython'>

并不是要求全部都要是值组,是要求 \序号 匹配的是值组:

>>> re.search(r"(I )love(Python)\2", "I lovePythonPython.com")
<_sre.SRE_Match object; span=(0, 18), match='I lovePythonPython'>

②如果跟着的数字是 0 或者 3位的数字,那么它是一个八进制数,表示的是这个八进制数对应的 ASCII 码对应的字符

例如:字符 0 对应的十进制数为 48,对应的八进制数为 60,这里要三位数,就是060,所以:

>>> re.search(r"\060", '0')
<_sre.SRE_Match object; span=(0, 1), match='0'>
>>> re.search(r"I love Python\060", 'I love Python0')
<_sre.SRE_Match object; span=(0, 14), match='I love Python0'>

接下来要介绍的元字符是 中括号([ ]),这是生成一个字符类,事实上,字符类就是一个字符集合的意思,另外,值的注意的是:被中括号包含在里面的元字符都会失去特殊功能,就像 反斜杠加上一个元字符是一样的,举例:

>>> re.search(r"[.]", 'I love Python.com')
<_sre.SRE_Match object; span=(13, 14), match='.'>

字符类的意思就是将它里面的内容都当做普通的字符看待,除了几个特殊的字符:

①小横杠(-),我们用它表示范围,我们上节课讲过,这节课我们讲一个其他的方法:re.findall()
在这里插入图片描述

>>> re.findall(r"[a-z]","12a32bc43jf3")
['a', 'b', 'c', 'j', 'f']

findall 和 search 相比,似乎更符合我们的需求,但是当遇到值组时,findall 也会有陷阱,我们后面会讲解。

②反斜杠(),把反斜杠放在字符类[ ]中,它也不是表示本身,这样会报错,

>>> re.findall(r"[\]","12a32bc43jf3")
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    re.findall(r"[\]","12a32bc43jf3")
  File "D:\ProgramFiles\Anaconda3\lib\re.py", line 213, in findall
    return _compile(pattern, flags).findall(string)
  File "D:\ProgramFiles\Anaconda3\lib\re.py", line 293, in _compile
    p = sre_compile.compile(pattern, flags)
  File "D:\ProgramFiles\Anaconda3\lib\sre_compile.py", line 536, in compile
    p = sre_parse.parse(p, flags)
  File "D:\ProgramFiles\Anaconda3\lib\sre_parse.py", line 829, in parse
    p = _parse_sub(source, pattern, 0)
  File "D:\ProgramFiles\Anaconda3\lib\sre_parse.py", line 437, in _parse_sub
    itemsappend(_parse(source, state))
  File "D:\ProgramFiles\Anaconda3\lib\sre_parse.py", line 545, in _parse
    source.tell() - here)
sre_constants.error: unterminated character set at position 0

反斜杠在字符类里,表示Python 字符串的转义符。

在字符串里,我们都知道 \n 表示回车的意思,所以:

>>> re.findall(r"[\n]","12a32\nbc43jf3")
['\n']

③托字符 ^,在字符类[ ]里,表示‘除了’(取反)的意思,但是要注意的是,这个托字符 ^ 必须放在最前面:

>>> re.findall(r"[^a-z]","12a32bc43jf3")
['1', '2', '3', '2', '4', '3', '3']

如果放在后面,就是表示匹配它本身:

>>> re.findall(r"[a-z^]","12a32bc^^43jf3")
['a', 'b', 'c', '^', '^', 'j', 'f']

最后要介绍的元字符 是用于做重复的事情,例如我们上节课讲到的 大括号{ },如{M,N}(要求M,N均为非负整数,且M<=N)表示前面的内容匹配 M~N次。

>>> re.search(r'Python{3}', 'I love Pythonnn')
<_sre.SRE_Match object; span=(7, 15), match='Pythonnn'>
>>> re.search(r'(Python){3}', 'I love PythonPythonPython')
<_sre.SRE_Match object; span=(7, 25), match='PythonPythonPython'>

在正则表达式中,需要注意的是,大家在写编程的时候,可能会注意美观,可能会多加一些空格,但是在正则表达式里面,你千万不能加空格,例如:

>>> re.search(r'(Python){1,5}', 'I love PythonPythonPython')
<_sre.SRE_Match object; span=(7, 25), match='PythonPythonPython'>
>>> re.search(r'(Python){1, 5}', 'I love PythonPythonPython')
>>> 

因为空格会被解析为一个正则表达式。

最后,我们来谈一下几个特殊的:

①星号(*):匹配前面的子表达式零次或多次,等价于 {0,}

②加号(+):匹配前面的子表达式一次或多次,等价于 {1,}

③问号(?):匹配前面的子表达式零次或一次,等价于 {0,1}

在正则表达式中,如果实现条件一样,推荐大家使用左边的 * + ?这三个,不要使用 大括号{ },因为:首先,星号、加号、问号更加简洁;其次,正则表达式内部会对这三个符号进行优化,效率会比使用大括号要高一些。

最后,我们来谈一下 贪婪非贪婪

关于我们这个 重复 的操作,有一点需要注意的就是:正则表达式默认是启用 贪婪 的模式来进行匹配的,那什么是 贪婪 呢?贪婪就是贪心,也就是说,只要在符合的条件下,它会尽可能多的去匹配,例如前面的 re.search(r’(Python){1,5}’, ‘I love PythonPythonPython’) 就会直接匹配到3个 Python。

我们来看一个现实中的案例。假设我们想 匹配

>>> s = "<html><title> I love Python.com</title></html>"
>>> re.search(r"<.+>", s)
<_sre.SRE_Match object; span=(0, 46), match='<html><title> I love Python.com</title></html>'>

<.+> 表示以 < 开头,以 > 结尾,重复 . 号 1次或多次。最后匹配了字符串全部。很明显,这不是我们想要的结果。

因为贪婪会在条件符合的情况下尽可能多的去匹配,既然是这样,我们就必须启用 非贪婪模式才可以,那么非贪婪模式怎么样启用呢?

很简单,在表示重复的元字符后面再加上一个问号,这时候,问号就不代表0次或1次了,而是表示启用非贪婪模式:

>>> re.search(r"<.+?>", s)
<_sre.SRE_Match object; span=(0, 6), match='<html>'>

猜你喜欢

转载自blog.csdn.net/qq_38970783/article/details/88641416
今日推荐