正则表达式是Python学习的一种基本匹配方法。先来一个题预预热:
如果要用正则表达式匹配“一张表情包出生于2018年3月28日”的出生年月日,该怎么做?
可以写出匹配方法来(\d{4}年\d{1,2}月\d{1,2}日)
怎么写出来的呢?先来了解一下基础知识:
1、常见的一些基础知识:
. 任意字符,换行符除外
\b 匹配单词的开始或者结束(e.g.:匹配say,可以用\bs\w*\b,单词的开始结束加上了\b)
\d 匹配数字
\w 匹配字母、数字、下划线或者汉字
\s 匹配任何空白符号
\B 匹配不是单词的开始或者结束(与上面\b相反)
\D 匹配不是数字的字符(与上面\d相反)
\W 匹配不是字母、数字、下划线或者汉字的字符(与上面\w相反)
\S 匹配任何非空白符号(与上面\s相反)
^ 匹配字符串的开始(前面加^)
$ 匹配字符串的结束 (后面加$)
* 重复0次或者多次(e.g.:\d*的意思就是数字不出现或者出现多少次都可以)
+ 重复1次或者多次
? 重复1次或者0次
{n} 重复了n次
{n,} 重复了n次或者更多的次数
{n,m} 重复了n次到m次
当要匹配的的字符中含有正则表达式本来就有的特殊符号时,我们可以用“\”来取消。(e.g.:匹配“.”时,用\.)
当要匹配一个集合时,可以使用[]。(e.g.:[abcdef]意思就是匹配abcdef中的任意一个字符)
当匹配时需要好几种匹配规则,这时候|就用上了。(e.g.:\d{4}|\s{1}匹配4个数字或者一个空白符)
正则表达式中,我们可以用()来进行分组,把想要一起操作或者提取的字符放在()中。
[^a] 匹配除了a之外的字符
[^abc] 匹配除了a、b、c之外的字符
[^(123|abc)] 匹配除了1、2、3或者a、b、c以外的字符
(?<name>exp) 匹配exp,然后将捕获的文本给name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获文本,也不分配组好(e.g.:有时候只是用()来限制范围,不需要捕获其中内容)
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
(?#comment) 注释(e.g.:(?#这是注释))
正则表达式匹配时是贪婪模式,也就是从后向前进行匹配。当我们用b.*b来匹配baaaaaaaaaaabb时,匹配出来的字符为bb。当我们需要的字符是baaaaaaaaaaabb时就需要非贪婪的匹配模式,这时我们只需要加一个?,匹配式就为?(b.*b)。但如果我们需要的是baaaaaaaaaaab时,只需要把最后最后一个b变成非贪婪模式,即为?(b.*?b)。
以上是正则表达式的语法应用,在Python中支持绝大部分,但是也有自己独特的一些匹配方法。
\A 仅匹配字符串开头
\Z 仅匹配字符串结尾
(?P<name>) 分组,除了原有的编号外,再外指定一个别名。(?P=name) 引用别名匹配的字符串。(e.g.:(?P<id>\d)(?P=id),此处后面id引用前面id的group)
Python中有re模块来支持正则表达式,分别介绍:
s=re.compile(r'\d'):将一个正则表达式转化成s匹配对象,用来接下来的匹配 。
re.match():输入参数string,用上面s来进行匹配。匹配成功返回结果,失败返回None。(e.g.:re.match(s,'123'),其实可以用正则表达式直接代替s)
re.search():search方法与match方法相似,区别在于match()只从string开始位置匹配,search()会扫描整个string查找匹配。
re.split():是将匹配的子串将返回的string切割成列表返回。
re.findall():搜索整个string,以列表形式返回匹配成功的全部子串。
re.finditer():搜索整个string,以迭代的方式返回匹配成功的全部Match对象。
re.sub(pattern,repl,string):是用repl替换string中每一个匹配的子串后,返回替换后的字符串。还可以用re.subn()来返回re.sub()替换次数。
此刻再看刚刚出的题,就有很多可能性了,匹配“一张表情包出生于2018年3月28日”可能出现各种各样的情况。比如出现“年月日”分别用-和\代替,写成2018-3-28或者2019\3\28。有的人可能只写到月份,没有日。结合Python,我们可以如下写:
import re line = "一张表情包出生于2018年3月28日" linezz = ".*出生于(\d{4}[年/-]\d{1,2}([月/-]\d{1,2}[日]|[月/-]\d{1,2}|[月]|$))" pa = re.match(linezz, line) if pa: print(pa.group(1))