正则表达式(英语:Regular Expression,在代码中常简写为 regex、regexp 或 RE),是计算机科学的一个概念,Regular Expression 即“描述某种规则的表达式”之意。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
在 Python 中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块,名字为 re。
import re # 使用match方法进行匹配操作 result = re.match(正则表达式, 要匹配的字符串) # 如果上一步匹配到数据的话,可以使用group方法来提取数据 result.group()
match():是用来进行正则匹配检查的方法,若字符串匹配正则表达式,则 match 方法返回匹配对象(Match Object),否则返回None。
group():匹配对象 Macth Object 具有 group 方法,用来返回字符串的匹配部分。
示例:
1 >>> import re 2 >>> result = re.match("hello", "hello world") # match() 能够匹配出以xxx开头的字符串 3 >>> result.group() 4 ‘hello‘
Python 中字符串前面加上 r 表示原生字符串。
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
Python 里的原生字符串很好地解决了这个问题,有了原始字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
1 >>> s = "\\a" 2 >>> s 3 ‘\\a‘ 4 >>> print(s) 5 \a 6 >>> 7 >>> ret = re.match("\\\\a", "\\a").group() # 转义 8 >>> ret 9 ‘\\a‘ 10 >>> print(ret) 11 \a 12 >>> ret = re.match(r"\\a", "\\a").group() # 原生字符串 13 >>> ret 14 ‘\\a‘ 15 >>> print(ret) 16 \a
正则表达式的单字符匹配如下:
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n) |
[ ] | 匹配[ ]中列举的字符;[^]中的^代表非 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即 空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符,即a-z、A-Z、0-9、_ |
\W | 匹配非单词字符 |
示例:
1 >>> import re 2 >>> result = re.match("嫦娥\d号", "嫦娥1号") 3 >>> result.group() 4 ‘嫦娥1号‘ 5 >>> result = re.match("嫦娥\d号", "嫦娥2号") 6 >>> result.group() 7 ‘嫦娥2号‘ 8 >>> result = re.match("[a-zA-Z]", "Hello World") 9 >>> result.group() 10 ‘H‘
匹配多个字符的相关格式:
字符 | 功能 |
---|---|
* | 匹配前一个字符出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现1次或者无限次,即至少有1次 |
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,} | 匹配前一个字符至少出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无:
1 >>> re.match("[A-Z][a-z]*", "Faaa").group() 2 ‘Faaa‘ 3 >>> re.match("[A-Z][a-z]*", "F").group() 4 ‘F‘
匹配出,变量命名是否有效:
1 >>> re.match("[a-zA-Z_]+[\w]*", "Name").group() 2 ‘Name‘ 3 >>> re.match("[a-zA-Z_]+[\w]*", "_Name").group() 4 ‘_Name‘ 5 >>> re.match("[a-zA-Z_]+[\w]*", "1_Name").group() 6 Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8 AttributeError: ‘NoneType‘ object has no attribute ‘group‘
匹配出,0到99之间的数字:
1 >>> re.match("[1-9]?[0-9]", "09").group() 2 ‘0‘ 3 >>> re.match("[1-9]?\d", "12").group() 4 ‘12‘ 5 >>> re.match("[1-9]?[0-9]", "100").group() 6 ‘10‘
匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线:
1 >>> re.match("[\w]{8,20}", "1234567").group() 2 Traceback (most recent call last): 3 File "<stdin>", line 1, in <module> 4 AttributeError: ‘NoneType‘ object has no attribute ‘group‘ 5 >>> re.match("[\w]{8,20}", "1234567a").group() 6 ‘1234567a‘ 7 >>> re.match("[\w]{8,20}", "1234567aA_").group() 8 ‘1234567aA_‘ 9 >>> re.match("[\w]{8,20}", "1234567aA_000000000000000000").group() 10 ‘1234567aA_0000000000‘
字符 | 功能 |
---|---|
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词边界 |
匹配 163.com 的邮箱地址:
1 >>> re.match("[\w]{4,20}@163\.com", "123aa_A@163.com").group() 2 ‘123aa_A@163.com‘ 3 >>> re.match("[\w]{4,20}@163\.com", "123aa_A@163.com_sada").group() 4 ‘123aa_A@163.com‘ 5 >>> re.match("[\w]{4,20}@163\.com$", "123aa_A@163.com_sada").group() 6 Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8 AttributeError: ‘NoneType‘ object has no attribute ‘group‘ 9 >>> re.match("[\w]{4,20}@163\.com$", "123aa_A@163.com").group() 10 ‘123aa_A@163.com‘
注意,\b 在正则中表示单词间隔,但 \b 在字符串里本身是个转义,代表退格。因此需要加 r 表示 正则中的单词间隔。
而相比于\b, 像 \w、\d 只有一种解释,并没有对应的转义字符,所以不加 r,也不会出错。
1 >>> re.match(r".*\bhello\b", "soda hello ver").group() 2 ‘soda hello‘ 3 >>> re.match(r".*\bhello\b", "soda hellover").group() 4 Traceback (most recent call last): 5 File "<stdin>", line 1, in <module> 6 AttributeError: ‘NoneType‘ object has no attribute ‘group‘ 7 >>> re.match(r".*\bhello\b", "hello ver").group() 8 ‘hello‘
1 >>> re.match(r".*\Bhello\B", "hellover").group() 2 Traceback (most recent call last): 3 File "<stdin>", line 1, in <module> 4 AttributeError: ‘NoneType‘ object has no attribute ‘group‘ 5 >>> re.match(r".*\Bhello\B", "_hellover").group() 6 ‘_hello‘ 7 >>> re.match(r".*\Bhello\B", "hello").group() 8 Traceback (most recent call last): 9 File "<stdin>", line 1, in <module> 10 AttributeError: ‘NoneType‘ object has no attribute ‘group‘
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
(ab) | 将括号中的字符作为一个分组 |
\num |
引用分组num匹配到的字符串 |
(?P<name>) |
分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
匹配出0-100之间的数字:
1 >>> re.match("[1-9]?\d", "08").group() 2 ‘0‘ 3 >>> re.match("[1-9]?\d$", "08").group() 4 Traceback (most recent call last): 5 File "<stdin>", line 1, in <module> 6 AttributeError: ‘NoneType‘ object has no attribute ‘group‘ 7 >>> re.match("[1-9]?\d$|100|0", "8").group() # 满足3组规则中的一组即可 8 ‘8‘ 9 >>> re.match("[1-9]?\d$|100", "78").group() 10 ‘78‘ 11 >>> re.match("[1-9]?\d$|100", "100").group() 12 ‘100‘
匹配出163、126、qq邮箱之间的数字:
1 >>> re.match("(\w+)@(163|126|qq)\.com$", "123a@qq.com").group() 2 ‘123a@qq.com‘ 3 >>> re.match("(\w+)@(163|126|qq)\.com$", "123a@163.com").group() 4 ‘123a@163.com‘ 5 >>> re.match("(\w+)@(163|126|qq)\.com$", "123a@163.coma").group() 6 Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8 AttributeError: ‘NoneType‘ object has no attribute ‘group‘
取出分组部分:
1 >>> ret = re.match("([^-]*)-(\d+)", "010-1321331") 2 >>> ret.group() 3 ‘010-1321331‘ 4 >>> ret.group(1) # 取出第一个分组 5 ‘010‘ 6 >>> ret.group(2) # 取出第二个分组 7 ‘1321331‘
匹配出<html><h1>www.itcast.cn</h1></html>:
1 >>> re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.itcast.cn</h1></html>").group() 2 ‘<html><h1>www.itcast.cn</h1></html>‘
匹配出<html><h1>www.itcast.cn</h1></html>:
1 >>> re.match(r"<(?P<key1>\w*)><(?P<key2>\w*)>.*</(?P=key2)></(?P=key1)>", "<html><h1>www.itcast.cn</h1></html>").group() 2 ‘<html><h1>www.itcast.cn</h1></html>‘
示例:
1 >>> re.search(r"\d+","预习次数为:2,复习次数为:6").group() # search 2 ‘2‘ 3 >>> re.findall(r"\d+","预习次数为:2,复习次数为:6") # findall 4 [‘2‘, ‘6‘] 5 >>> re.sub("\d+", "998", "python = 997") # sub 6 ‘python = 998‘ 7 >>> re.split(":| ", "info:xiaoZhang 22 shandong") # split,分隔符为冒号或空格 8 [‘info‘, ‘xiaoZhang‘, ‘22‘, ‘shandong‘]
sub 的第二种用法,传递函数作为参数:
1 import re 2 3 def add_one(ret): 4 str_num = ret.group() 5 return str(int(str_num)+1) 6 7 ret = re.sub("\d+", add_one, "python = 997") 8 print(ret) # python = 998
练习题:从下面的字符串中取出文本
<div> <p>岗位职责:</p> <p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p> <p><br></p> <p>必备要求:</p> <p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p> <p> <br></p> <p>技术要求:</p> <p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p> <p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p> <p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p> <p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p> <p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p> <p> <br></p> <p>加分项:</p> <p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p> </div>
1 # 方法一:精确匹配 2 re.sub("</?\w*>", "", raw_str) 3 4 # 方法二:使用非贪婪模式 5 re.sub("<.+?>", "", raw_str)
Python 中正则表达式的数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),当它在从左到右的顺序求值时,总是尝试匹配尽可能多的字符。非贪婪则相反,总是尝试匹配尽可能少的字符。
在 "*"、"?"、"+"、"{m,n}" 后面加上?,可使贪婪变成非贪婪。
示例1:
1 >>> re.match(".+(\d+-\d+-\d+-\d+)", s).group(1) 2 ‘4-235-22-423‘ 3 >>> re.match(".+?(\d+-\d+-\d+-\d+)", s).group(1) 4 ‘234-235-22-423‘
在上面的例子中,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。
因此解决方式为使用非贪婪操作符“?”,要求正则匹配的越少越好。
示例2:
1 >>> re.match("aa(\d+)", "aa1232ddd").group(1) 2 ‘1232‘ 3 >>> re.match("aa(\d+?)", "aa1232ddd").group(1) 4 ‘1‘ 5 >>> re.match("aa(\d+)ddd", "aa1232ddd").group(1) 6 ‘1232‘ 7 >>> re.match("aa(\d+?)ddd", "aa1232ddd").group(1) 8 ‘1232‘
有一批网址:
http://www.interoem.com/messageinfo.asp?id=35 http://3995503.com/class/class09/news_show.asp?id=14 http://lib.wzmc.edu.cn/news/onews.asp?id=769 http://www.zy-ls.com/alfx.asp?newsid=377&id=6 http://www.fincm.com/newslist.asp?id=415
需要正则后为:
http://www.interoem.com/ http://3995503.com/ http://lib.wzmc.edu.cn/ http://www.zy-ls.com/ http://www.fincm.com/
答:
1 # 方法一 2 re.match(r"http://.*?/", s).group() 3 4 # 方法二:使用替换,仅返回需要的部分 5 re.sub(r"(http://.*?/).*", lambda x: x.group(1), s)
有一句英文“hello world ha ha”,查找其中所有的单词:
1 >>> s = "hello world ha ha" 2 >>> re.split(" ", s) # 方法一 3 [‘hello‘, ‘world‘, ‘ha‘, ‘ha‘] 4 >>> re.findall("\w+", s) # 方法二 5 [‘hello‘, ‘world‘, ‘ha‘, ‘ha‘]
原文:https://www.cnblogs.com/juno3550/p/12345857.html