正则表达式的英文为“Regular Expression”,在计算机编程中简写为regex、regexp或RE,其中“Regular”翻译为“正则”、“正规”、“常规”、“规则”、“规律”,“Regular Expression”可以理解为“描述某种规则的表达式”。
在Python中,正则表达式是一种强大的文本处理工具,它能够以某个规则匹配、搜索、替换或拆分复杂的字符串,被广泛运用于字符串处理、文本分析、数据挖掘等领域。正则表达式在程序开发中会经常用到,比如在登录页面对输入的字符串进行合法性验证,在输入邮箱用户名时,系统会对输入的内容进行合法性验证,邮箱用户名可以包含字母、数字、点号“.”、加号“+”和下划线“_”,但不能以点号开头或结尾,后加“@”以及邮箱地址等,如果不符合邮箱用户名的格式,就会报错,这里所使用的验证方式一般就是正则表达式。
正则表达式语法
1、普通字符
普通字符包括所有大小写字母、所有数字、所有标点符号和一些其它符号。如果想要判断一个字符串是否为数字(即判断是否为0~9的十个数字中任意一个数字),如果按传统的方法,我们可能需要通过10个条件去判断这个字符串是否等于这10个数字,那么通过正则表达式判断可以更加简便。例如:
一、正则表达式判断一个字符串是否为数字:
[0123456789]
方括号“[]”表示匹配指定范围内的字符,[0123456789]可以匹配0到9中任意一个数字,只要输入的数字和方括号中任意一个数字相同,即为匹配成功。 然而,把每个字符都列出来太麻烦了,所以Python规定如果字符是连续有序的,可以用“-”省略。所以,可以改写为:
[0-9]
二、正则表达式判断一个字符串是否为小写字母或大写字母:
[a-z] # 判断一个字符串是否为小写字母
[A-Z] # 判断一个字符串是否为大写字母
如果想要判断一个字符串是否为小写字母,正则表达式可以写成“[a-z]”;判断一个字符串是否为大写字母,正则表达式可以写成“[A-Z]”。这里需要注意的是,判断所有的英文字母(包括大写和小写),不能直接用[A-z]来表示,因为从小写字母到大写字母的ASCII码并不连续,正确的表达方式应该为:
[A-Za-z] #或者 [a-zA-Z]
三、正则表达式判断字符串的长度:
# 判断字符串是否为一个两位数字
[0-9][0-9]
# 判断字符串是否为一个三位数字
[0-9][0-9][0-9]
从上面的例子中可以看出,想要判断一组字符串是否为几位数字,就用几对方括号表示,每对方括号表示一位数字。
四、正则表达式判断输入的字母是大写的“N”或者是小写的“n”:
[Nn]
判断输入的字母是大写的“N”或者是小写的“n”,可以写出“[Nn]”,但是如果要判断New或new,相同的部分只要写一遍即可:
[Nn]ew
五、正则表达式匹配[...]中的所有字符:
[aeiou]
上面的例子中,我们利用[aeiou]匹配字符串“google runoob taobao”中所有的a、e、i、o、u字母,匹配结果有10处:“o”,“o”,“e”,“u”,“o”,“o”,“a”,“o”,“a”,“o”。
2、字符转义
0~9的数字范围正则表达式为“[0-9]”,其中“-”代表的是一个范围,而不是符号“-”本身,但是如果想要判断字符是不是在“0”,“-”,“9”这三个字符中的一个,就必须使用转义字符了。
在Python中,字符转义是一种特殊的方式来表示不能直接显示的字符,通常是通过在字符前面加上反斜杠“\”来实现的,下面我们用字符转义解决上述问题:
[0\-9] # 匹配“0”,“-”,“9”三个字符中的任意一个字符
这里需要注意的是,在Python中还有很多类似“-”这样不能直接显示的字符,包括“[”、“]”、“+”、“^”、“$”、“(”、“)”、“*”、“{”、“}”、“|”等,我们称这类有特殊意思的符号为元字符。
3、元字符
前面已经介绍了,0~9的数字范围正则表达式可以写成“[0-9]”,其中的“-”表示范围,并不表示字符“-”本身,像这类字符我们称之为元字符。
下表列出了正则表达式中的元字符:
元字符 | 描述 |
---|---|
[] | 用来定义一个字符集合,它将匹配方括号“[]”中的任意一个字符。例如[abc] 将匹配“a”,“b”, 或“c”中的任意一个字符 |
\ | 将下一个字符标记为一个特殊字符或一个原义字符。例如“n”匹配字符“n”,“\n”匹配一个换行符,“\\”匹配“\”,“\(”匹配“(” |
. | 匹配任意1个字符(除了换行符)。例如“a.c”可以 匹配“abc”、“a2c”、“a6c” |
* | 匹配前面的子表达式0次或多次。例如“ a*” 可以匹配“”、“a”、 “aaa” |
^ | 匹配字符串的开头,例如“^abc”可以匹配“abc123456” |
$ | 匹配字符串的末尾,例如“abc$”可以匹配“123456abc” |
+ | 匹配前面的子表达式一次或多次。例如“a+”可以匹配“a”、“aa”、“aaa” |
? | 匹配前面的子表达式0次或一次。例如“a?”可以匹配 “”、“a” |
{n} | n是一个非负整数,匹配前一个字符出现n次。例如“a{3}”可以匹配“aaa” |
{n,} | n是一个非负整数,匹配前一个字符至少出现n次。例如“o{2,}”不能匹配“does”中的“o”,但能匹配“goooood”中的所有“o”,注意{n,}里面不能有空格 |
{n,m} | m和n均为非负整数,其中n≤m。最少匹配n次,且最多匹配m次。例如“a{2,4} 可以匹配“aa”、“aaa”、“aaaa”,注意{n,m}里面不能有空格 |
x|y | 匹配x或y。例如,“g|food”能匹配“g”或“food”。“(g|f)ood”则匹配“good”或“food” |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“and”中的“a” |
[^xyz] | 否定字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“and”中的“n”,“d” |
[a-z] | 字符范围,匹配指定范围内的任意字符。例如“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符 |
[^a-z] | 否定字符范围。匹配不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符 |
\A | 匹配字符串的开头 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如“es\b”可以匹配“does”中的“es”,但不匹配“test”中的“es” |
\B | 匹配非单词边界。例如“es\B”能匹配“test”中的“es”,但不能匹配“does”中的“es” |
\d | 匹配一个数字字符,等价于“[0-9]” |
\D | 匹配一个非数字字符,等价于“[^0-9]” |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
\w | 匹配包括下画线的任何单词字符,等价于“[A-Za-z0-9_]” |
\W | 匹配任何非单词字符,等价于“[^A-Za-z0-9_]” |
\z | 匹配字符串结束 |
\Z | 匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等,等价于“[\f\n\r\t\v]” |
\S | 匹配任何非空白字符,等价于“[^\f\n\r\t\v]” |
() | 实现分组匹配,例如(\d{4})和(\d{7})可以分别捕获数据“张三,0123-3456789”中“0123”和“3456789”两组数据 |
4、限定符
在正则表达式中,限定符用于指定模式的匹配次数或匹配范围。re模块提供了多种不同的限定符,包括“*”、“+”、“?”、“{n}”、“{n,}”和“{n, m}”,这些限定符可以实现更灵活和精确的匹配操作,下一节教程中将会详细讲解re模块。
“*”限定符:表示匹配前一个字符的0次或多次重复。例如,正则表达式“a*”可以匹配空字符串、“a”、“aa”、“aaa”……等。
“+”限定符:表示匹配前一个字符的一次或多次重复。例如,正则表达式“a+”可以匹配“a”、“aa”、“aaa”……等。
“?”限定符:表示匹配前一个字符的0次或一次重复。例如,正则表达式“a?”可以匹配空字符串或“a”。
“{n}”限定符:用于指定前一个字符的精确重复次数。例如,正则表达式“a{3}”可以匹配“aaa”。
“{n,m}”限定符:用于指定前一个字符重复的范围,最少匹配n次,且最多匹配m次。例如,正则表达式“a{2,4}”可以匹配“aa”、“aaa”、“aaaa”,注意{n,m}里面不能有空格。
“{n,}”限定符:用于指定前一个字符重复的最小次数。例如,正则表达式“a{2,}”可以匹配“aa”、“aaa”、“aaaa”……等,注意{n,}里面不能有空格。
5、定位符
在正则表达式中,定位符能够将正则表达式固定到行首或行尾,用来描述字符串或单词的边界,“^”匹配字符串开始的位置,“$”匹配字符串结束的位置,“\b”匹配单词的前或后边界,“\B”匹配非单词的边界。
“^”定位符:指定模式匹配必须从字符串第一个字符开始,例如“[a-z]+”能匹配a~z的小写字母一次或多次,所以可以匹配“789xyz”中的“xyz”,但“^[a-z]+”不可以匹配“789xyz”中的“xyz”,因为“xyz”并不在字符串的开头。
“$”定位符:指定前面的模式必须出现在字符串的结尾,例如“[a-z]+”可以匹配“xyz789”中的“xyz”,但“[a-z]+$”不可以匹配“xyz789”中的“xyz”,它可以匹配“789xyz”中的“xyz”。
“\b”定位符:指定匹配必须在一个单词的边界上,单词边界是指单词和单词之间的位置,或者是单词和标点符号、换行符等之间的位置。“\b”在匹配时非常有用,可以匹配出某个完整的单词而不是单词中的一部分。例如,“\bis\b”在“This is a test”句子中只匹配完整的单词“is”,而不会匹配到“This”中的“is”。“\bapple\b”在“I have an apple. I love apples.”句子中只匹配完整的单词“apple”,而不会匹配到“apples”。
“\B”定位符:指定匹配不能出现在单词边界上,与“\b”相反,例如“\Bad\w+”意味着找到不以“ad”开头的单词,例如可以匹配“lady”中的“ady”;对于“address”,则无法匹配。
6、正则表达式中“^”符号的两种不同用法
有人会不理解,在正则表达式中,“^”符号为什么即可以匹配字符串的开头,又可以起到否定的作用,两种用法不是相互矛盾吗?其实没有矛盾,我们可以根据“^”符号出现的位置,实现两种不同的用法。
(1)在正则表达式的开头位置
如果“^”符号出现在正则表达式的开头位置,则可以匹配字符串的开头。例如:
动手练一练:
import re
a = "Hello, World!"
b = re.findall(r'^Hello', a)
print(b) # 输出: ['Hello']
执行以上代码,输出结果为:
['Hello']
上面的例子中,“^Hello”匹配了目标字符串的开头部分,因此只匹配到字符串 "Hello" 。
(1)在字符集中的开头位置
如果“^”符号出现在字符集中的开头位置,则表示否定字符集,字符集用方括号“[]”表示。例如,正则表达式 [^0-9] 表示匹配除了数字之外的任何字符。它将匹配任何非数字字符。例如:
动手练一练:
import re
a = "Hello, 123!"
b = re.findall(r'[^0-9]', a)
print(b) # 输出: ['H', 'e', 'l', 'l', 'o', ',', ' ', '!']
执行以上代码,输出结果为:
['H', 'e', 'l', 'l', 'o', ',', ' ', '!']
上面的例子中,[^0-9] 匹配了目标字符串中的所有非数字字符,包括空格,匹配结果输出一个列表。
因此,可以根据“^”符号出现的位置,实现两种不同的用法,两种用法没有相互矛盾。