文章目录
1.正则概念
正则表达式也叫作匹配模式,是由一组具有特殊含义的字符组成,通常是用来匹配和替换字符串,它是一门独立技术,用途的话,比如爬网页提取图片和文字啥的,使用正则表达式可使用正则模块“re”,引入的话可以使用以下带代码
import re
2.1.正则匹配
匹配和替换和正则表达式的主要功能,所以而替换的前提是匹配,所以正则表达式中,涉及到匹配的match方法和search方法,将是众多其他方法使用的前提,必须熟练掌握。
2.1.1.match方法
描述:尝试从字符串的起始位置进行匹配,如果不是起始位置匹配成功的话,match() 就返回 none,否则就返回一个匹配对象。
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
举例说明
> s1 = "my name is xuquanwen"
>>> m1 = re.match("my",s1)
>>> m2 = re.match("is",s1)
>>> print(m1)
<re.Match object; span=(0, 2), match='my'>
>>> print(m2)
None
>>>
就像之前描述的那样,“my”字符串位于s1字符串中匹配到的第一个,所以返回了一个对象给m1,而"is"字符串位于s1字符串中匹配到的第三个所以返回空也就是None.
2.1.2.匹配对象使用
当然match方法匹配到的对象肯定是要使用的,它的使用方法则可以使用分组中的group(num) 或 groups() 匹配对象函数来获取匹配表达式。这里也会简单先提一下“位数”和“元字符”等概念,不过下文也会更详细讲述。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号 |
举例说明
>>> m3 = re.match("(.*) (.*) (.*) (.*)",s1)
>>> m3.group()
'my name is xuquanwen'
>>> m3.group(1)
'my'
>>> m3.group(2)
'name'
>>> m3.group(3)
'is'
>>> m3.group(4)
'xuquanwen'
>>> m3.groups()
('my', 'name', 'is', 'xuquanwen')
>>>
*这里简单解释下上述代码,此处使用“(. * ) (. * )”表示分组,有两个括号间的空格来加以分割,"."的意义表示除了换行符外任意字符,则表示任意多个,简单来说就是用单独匹配出每个单词,group()默认值参数为0,即输出整个字符串。
2.1.3.search方法
描述:re.search 扫描整个字符串并返回第一个成功的匹配。
函数语法:
re.search(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
参数和match没啥区别,只不过match匹配条件是否是第一个,即严格要求条件为匹配字符串必须是被匹配字符串的子串,且匹配子串必须从被匹配字符串的头部开始。而search则是只要有子串就能匹配成功,同样的匹配成功re.search方法返回一个匹配的对象,否则返回None。
老规矩举例说明
>>> s = re.search("is",s1)
>>> s
<re.Match object; span=(8, 10), match='is'>
>>> s.group()
'is'
>>> s = re.search("sfsd",s1)
>>> s
>>> print(s)
None
>>>
通过上述代码可知,re.search仅仅只是匹配是否子串而已,比match无疑要宽松很多。刚刚我们也讲了可以用分组的方法使用match方法的匹配对象,对于search方法的匹配对象同样适用。
>>> s3 = re.search("(.*) (.*) (.*) .*",s1)
>>> s3.group()
'my name is xuquanwen'
>>> s3.group(1)
'my'
>>> s3.group(2)
'name'
>>> s3.group(3)
'is'
>>> s3.group(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: no such group
>>> s3.groups()
('my', 'name', 'is')
>>>
匹配方法就简单讲述到这里,下面我们看看其他几个检索和替换的方法。
3.正则检索和替换
个人才疏学浅用的少,主要还是用在爬网页中把html代码干掉。其他用处就不知道(暂时)了。学爬虫的话,反正是有用的。
3.1.sub方法
描述:sub方法的话主要用在替换字符串中。
语法:
re.sub(pattern, repl, string, count=0, flags=0)
参数:
参数 | 功能 |
---|---|
pattern | 正则中的模式字符串。 |
repl | 替换的字符串,也可为一个函数。 |
string | 要被查找替换的原始字符串。 |
count | 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 |
>>> sss
'<body><ul><li><a href="#">友情链接</a></li><li><a href="#">友情链接</a></li><li
><a href="#">友情链接</a></li><li><a href="#">友情链接</a></li><li><a href="#">
友情链接</a></li><li><a href="#">友情链接</a></li></ul></body>'
>>> re.sub("</?.+?>","",sss)
'友情链接友情链接友情链接友情链接友情链接友情链接'
4.正则表达式符号
即用来表示字符类型的字符
4.1.元字符
格式 | 作用 |
---|---|
\d | 匹配数字 |
. | 匹配任意符号除了换行符 |
\w | 匹配所有有效符号(大小写字母、数字、下划线、各国语言符号) |
\s | 匹配空白位(空格、\t) |
^ | 匹配以XXX开头 例如:以1开头 ^1 |
$ | 以XXX结尾 |
[] | 列举 [0123456789] 等价于 \d [a-z]表示所有小写字母 [A-Za-z0-9]表示所有有效字符,[A-Za-z]表示大小写字母 |
>>> import re
>>> re.match(".","1")
<re.Match object; span=(0, 1), match='1'>
>>> re.match(".","\n")
>>> re.match("...","abc")
<re.Match object; span=(0, 3), match='abc'>
>>> re.match("...","abcdef")
<re.Match object; span=(0, 3), match='abc'>
>>> re.match(".","\rabcdef")
<re.Match object; span=(0, 1), match='\r'>
>>> re.match("\d","a")
>>> re.match("\d","5")
<re.Match object; span=(0, 1), match='5'>
>>> re.match("\d","5567")
<re.Match object; span=(0, 1), match='5'>
>>> re.match("\d\d","5567")
<re.Match object; span=(0, 2), match='55'>
>>> re.match("\w","5")
<re.Match object; span=(0, 1), match='5'>
>>> re.match("\w","_")
<re.Match object; span=(0, 1), match='_'>
>>> re.match("\w","&")
>>> re.match("\w","^")
>>> re.match("\s"," ")
<re.Match object; span=(0, 1), match=' '>
>>> re.match("\s","\t\t")
<re.Match object; span=(0, 1), match='\t'>
>>> re.match("^1","123")
<re.Match object; span=(0, 1), match='1'>
>>> re.match("^1","212")
>>> re.match("^1.*","aaaaffff")
>>> re.match("^1.*","1aaaaffff")
<re.Match object; span=(0, 9), match='1aaaaffff'>
>>> re.findall("^1","aaaffff")
[]
>>> re.findall("^1","aaaff12ff")
[]
>>> re.findall("^1","12aaaff12ff")
['1']
>>> re.findall("^1.*","12aaaff12ff")
['12aaaff12ff']
>>> re.match("^1\d*","18")
<re.Match object; span=(0, 2), match='18'>
>>> re.match("^1\d*$8","18")
>>> re.match("^1\d*8$","18")
<re.Match object; span=(0, 2), match='18'>
>>> re.match("8$","18")
>>> re.match("$8","18")
>>> re.match("[12345678]","18")
>>>> re.match("[a-z]","ttt")
<re.Match object; span=(0, 1), match='t'>
>>> re.match("[a-z]*","ttt")
<re.Match object; span=(0, 3), match='ttt'>
>>> re.match("[a-z]*","tsdfsfdasdas")
<re.Match object; span=(0, 12), match='tsdfsfdasdas'>
>>> re.match("[A-Z]*","WORLD")
<re.Match object; span=(0, 5), match='WORLD'>
>>> re.match("[A-Za-z]*","WORLD love nature")
<re.Match object; span=(0, 5), match='WORLD'>
>>> re.match("[A-Za-z]*","WORLDlovenature")
<re.Match object; span=(0, 15), match='WORLDlovenature'>
>>> re.match("[A-Za-z0-9]*","WORLDlovenature1998")
<re.Match object; span=(0, 19), match='WORLDlovenature1998'>
>>> re.match("[0-9A-Za-z]*","WORLDlovenature1998")
<re.Match object; span=(0, 19), match='WORLDlovenature1998'>
>>> re.match("[0-9a-zA-z]*","WORLDlovenature1998")
<re.Match object; span=(0, 19), match='WORLDlovenature1998'>
<re.Match object; span=(0, 1), match='1'>
>>> re.match("我今年\d岁了","我今年18岁了")
>>>
>因为\d只会匹配数字
4.2 反义符
格式 | 作用 |
---|---|
\D | 不是数字 |
\W | 特殊符号 |
\S | 非空白位 |
>>> re.match("\D","2")
>>> re.match("\D","ee")
<re.Match object; span=(0, 1), match='e'>
>>> re.match("\W","ee")
>>> re.match("\W","^")
<re.Match object; span=(0, 1), match='^'>
>>> re.match("\S"," ")
>>> re.match("\S","sd")
<re.Match object; span=(0, 1), match='s'>
注意:[ ^ ]-------- 列举反义 注意 ^ []和 [ ^ ]的区别
4.3 转义符
在python中如果字符串中含有\是具有特殊含义的,如果要表示一个正常等等\n,需要有两个\
>>> s = "hello\n world "
>>> s
'hello\n world '
>>> print(s)
hello
world
>>> s = "hello\\n world "
>>> print(s)
hello\n world
>>>
在正则里表达式中反斜杠是有特殊含义的,如果要表示一个正常的反斜杠需要两个反斜杠表示
>>> re.match("C:\\a\\b\\c",path)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "E:\py\lib\re.py", line 191, in match
return _compile(pattern, flags).match(string)
File "E:\py\lib\re.py", line 304, in _compile
p = sre_compile.compile(pattern, flags)
File "E:\py\lib\sre_compile.py", line 764, in compile
p = sre_parse.parse(p, flags)
File "E:\py\lib\sre_parse.py", line 948, in parse
p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
File "E:\py\lib\sre_parse.py", line 443, in _parse_sub
itemsappend(_parse(source, state, verbose, nested + 1,
File "E:\py\lib\sre_parse.py", line 525, in _parse
code = _escape(source, this, state)
File "E:\py\lib\sre_parse.py", line 426, in _escape
raise source.error("bad escape %s" % escape, len(escape))
re.error: bad escape \c at position 6
>>> re.match("C:\\\\a\\\\b\\\\c",path)
<re.Match object; span=(0, 8), match='C:\\a\\b\\c'>
>>>
这里正则转义一次
>>> s = "\\\\\\"
>>> s
'\\\\\\'
>>> print(s)
\\\
可用r表示正则
>>> re.match(r"C:\\a\\b\\c",path)
<re.Match object; span=(0, 8), match='C:\\a\\b\\c'>
建议大家在正则使用中加上r
5 位数
即在指定正则生效的实际范围
>>> s = "我今年18,明年19"
>>> s
'我今年18,明年19'
>>> re.findall(r"\d",s)
['1', '8', '1', '9']
>>> re.findall("\d",s)
['1', '8', '1', '9']
后面加*表示匹配任意位
后面加+表示至少有一位,可以有n位
? 表示0位或者1位
{n,} 至少n位i
{n,m} n到m的区间,m可以超出最大值
>>> re.findall(r"1[356789]\d{7,}","133456789")
['133456789']
>>> re.findall(r"1[356789]\d{6,}","133456789")
['133456789']
>>> re.findall(r"1[356789]\d{1,2}","1334567891")
['1334']
>>> re.findall(r"1[356789]\d{1,8}","1334567891")
['1334567891']
>>> re.findall(r"1[356789]\d{1,7}","1334567891")
['133456789']
>>> re.findall(r"1[356789]\d{1,9}","1334567891")
['1334567891']
>>> re.findall(r"1[356789]\d{1,10}","1334567891")
['1334567891']
需要提一下的是?,其作为非贪婪匹配可以如下组合’a*?',即匹配遇到的第一个a,而如果是’a*'则会直接匹配到最后一个a.
6.分组
正则表达式中,使用()将正则包裹起来,形成一个分组,目的是为了匹配后的二次匹配
>>> s = "我今年18,我明年23"
>>> import re
>>> res = re.match(r".*(\d)+.*",s)
>>> res
<re.Match object; span=(0, 11), match='我今年18,我明年23'>
>>> res.group(1)
'3'
>>> res.group(0)
'我今年18,我明年23'
>>> res.group(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: no such group
>>> res = re.match(r".*?(\d+).*",s)
>>> res.group(1)
'18'
>>> res.group(0)
'我今年18,我明年23'
>>> res = re.match(r"(\d{4})-(\d{4})","1234-5678")
>>> res
<re.Match object; span=(0, 9), match='1234-5678'>
>>> res.group()
'1234-5678'
>>> res.group(1)
'1234'
>>> res.group(2)
'5678'