正则表达式最全教程(含⽰例代码)
⽬录
1.概述
使⽤正则表达式可以为匹配的可能字符串集指定规则;可以判断此字符串是否与模式匹配等问题。还可以使⽤正则表达式修改字符串或以各种⽅式将其拆分。
正则表达式模式被编译成⼀系列字节码,然后由⽤C 编写的匹配引擎执⾏。对于⾼级⽤途,可能需要特别注意引擎如何执⾏给定的正则,并将正则写⼊以某种⽅式⽣成运⾏速度更快的字节码。
2.简单模式
我们⾸先要了解最简单的正则表达式。由于正则表达式⽤于对字符串进⾏操作,因此我们将从最常见的任务开始:匹配字符。
元字符的完整列表如下:
. ^ $ * + ? { } [ ] \ | ( )
这些元字符有的可以⽤来表⽰匹配字符,有的可以⽤来表⽰字符重复次数,下⾯依次介绍这些元字符。
2.1 匹配字符
1.[ ]:⽤于指定字符类,⾥⾯放你希望匹配的⼀组字符。既可以单独列出字符,也可以通过给出两个字符并⽤’-'标记将他们分开来表⽰⼀系列字符。
例如:
[a-z]:⽤来匹配⼩写字符
[abc]:可以匹配a或b或c,这与[a-c]
相同。
字符类中的元字符是不⽣效的,例如:[akm$]将匹配a或k或m或$,$通常是⼀个元字符,但是在字符类中它不⽣效
2. ^:⽤于匹配字符类未列出的字符。通过包含^作为作为字符类的第⼀个字符来表⽰。
例如:
[^5]:匹配除5之外的任何字符
如果该字符出现在字符类的其他位置,则没有特殊含义
[5^]:匹配5或者 ^
3.‘\’字符:后⾯可以跟各种字符,以指⽰各种特殊序列
它也可以⽤于转义所有元字符。如果你需要匹配 [ 或 \ ,可以在他们的前⾯加上⼀个反斜杠来转义他们的特殊含义。即 \[ 或 \\⼀些以\开头的特殊序列表⽰预定义的字符集,例如字符集、字母集或任何⾮空格的集合。
\d 匹配任何⼗进制数字;这等价于类[0-9]。
\D 匹配任何⾮数字字符;这等价于类[^0-9]。
\s 匹配任何空⽩字符;这等价于类[ \t \n \r \f \v]。
\S 匹配任何⾮空⽩字符;这相当于类[^ \t\n\r\f\v]。
\w 匹配任何字母与数字字符;这相当于类[a-zA-Z0-9_]。
\W 匹配任何⾮字母与数字字符;这相当于类[^a-zA-Z0-9_]。
4. ’ . '字符:⽤来匹配除换⾏符之外的任何内容。但是有⼀个可选模式(re.DOTALL)可以匹配换⾏符
2.2. 重复
匹配不同的字符集是正则表达式可以做的第⼀件事情,另⼀个功能是可以指定正则表达式的某些部分必须重复⼀定次数。
5. ’ * '字符:它指定前⼀个字符可以匹配零次或多次。
例如:ca*t 将匹配’ ct ’ (0 个’a’ 字符),’ cat ’ (1 个’a’ ),’ caaat ’ (3 个’a’ 字符),等等
类似 * 这样的重复是贪婪的;当重复正则时,匹配引擎将尝试尽可能多地重复它。如果模式的后续部分不
匹配,则匹配引擎将回退并以较少的重复次数再次尝试
6. ’ + '字符:它指定前⼀个字符可以匹配⼀次或多次。
ca+t 将匹配’cat’ (1 个’a’),‘caaat’ (3 个’a’),但不会匹配’ct’。
7. ’ ? '字符:它指定前⼀个字符可以匹配⼀次或零次。
可以把它想象成是可选的。例如,home-?brew 匹配’homebrew’ 或’home-brew’。
7. ’ ?{m, n}'字符:这个是最复杂的重复限定符是,其中m 和n 是⼗进制整数。这个限定符意味着必须⾄少重复m 次,最多重复n 次。
例如,a/{1,3}b 将匹配’a/b’ ,‘a//b’ 和’a///b’ 。它不匹配没有斜线的’ab’,或者有四个的’ab’。
可以省略m 或n; 在这种情况下,将假定缺失值的合理值。省略m 被解释为0 下限,⽽省略n 则为⽆穷⼤
的上限。
可以看出{0,} 与* 相同,{1,} 相当于+ ,{0,1} 和? 相同。建议最好使⽤* ,+ 或? ,因为他们更短更易阅读。
3.使⽤正则表达式
有了上⾯的了解,下⾯介绍在python中实际使⽤它们,re模块提供了正则表达式引擎的接⼝,允许你将正则编译成对象,然后⽤它们进⾏匹配。
3.1 编译正则表达式
正则表达式被编译成模式对象,模式对象具有各种操作的⽅法,例如搜索模式匹配或执⾏字符串替换。
>>>import re
>>> p = repile('ab*')
>>> p
repile('ab*')
repile() 也接受⼀个可选的flags 参数,⽤于启⽤各种特殊功能和语法变体。后⾯会介绍可⽤的设置,但现在只举⼀个例⼦
>>> p = repile('ab*', re.IGNORECASE)
正则作为字符串传递给repile() 。正则被处理为字符串,因为正则表达式不是核⼼Python语⾔的⼀部分,并且没有创建⽤于表达它们的特殊语法。
3.2 反斜杠灾难
将正则放在字符串中可以使Python 语⾔更简单,但有⼀个缺点就是反斜杠灾难。
正则表达式使⽤反斜杠字符(’\’) 来表⽰特殊形式或允许使⽤特殊字符⽽不调⽤它们的特殊含义。
假设你想要编写⼀个与字符串\section 相匹配的正则。要出在程序代码中写⼊的内容,从要匹配的字符串开始,接下来,必须通过在反斜杠前⾯添加反斜杠从⽽产⽣字符串’\\section’,但是,要将其表⽰为Python 字符串⽂字,必须再次转义两个反斜杠,即’\\\\section’。
简⽽⾔之,要匹配⽂字反斜杠,必须将’\\’ 写为正则字符串,因为正则表达式必须是\,并且每个反斜杠必须表⽰为\\
解决⽅案是使⽤Python 的原始字符串表⽰法来表⽰正则表达式;在前缀为’r’ 的字符串中,反斜杠不以
任何特殊的⽅式处理,因此r"\n" 是⼀个包含’\’ 和’n’ 的双字符字符串,⽽"\n" 是⼀个包含换⾏符的单字符字符串。正则表达式通常使⽤这种原始字符串表⽰法⽤Python 代码编写。
此外,在正则表达式中有效但在Python 字符串⽂字中⽆效的特殊转义序列会导致DeprecationWarning,最终变为SyntaxError。这意味着如果未使⽤原始字符串表⽰法或转义反斜杠,序列将⽆效。
3.3 应⽤匹配
当编译正则表达式之后就得到了模式对象,下⾯介绍最终的模式对象的⽅法和属性:
python正则表达式不包含⽅法/属
性
⽬的
match()从字符串的开头匹配。没有到匹配,返回None,成功则返回匹配对象的实例,包含匹配相
关的信息:起始和终⽌位置、匹配的⼦串等的。
search()扫描字符串,查此正则匹配的任何位置。没有到匹配,返回None,成功则返回匹配对象的实例,包含匹配相关的信息:起始和终⽌位置、匹配的⼦串等的。
findall()到正则匹配的所有⼦字符串,并将它们作为列表返回。
finditer()到正则匹配的所有⼦字符串,并将它们返回为⼀个iterator。
⽰例:
>>>import re
>>> p = repile('[a-z]+')
>>> p
repile('[a-z]+')
你可以尝试匹配正则[a-z]+ 的各种字符串。空字符串根本不匹配,因为+ 表⽰“⼀次或多次重复”。
match() 在这种情况下应返回None,这将导致解释器不打印输出。你可以显式打印match() 的结果。
>>> p.match("")
>>>print(p.match(""))
None
现在,让我们尝试⼀下它应该匹配的字符串,例如tempo。在这个例⼦中match() 将返回⼀个匹配对象,因此你应该将结果储存到⼀个变量中以供稍后使⽤。
>>> m = p.match('tempo')
>>> m
<re.Match object; span=(0,5), match='tempo'>
你可以检查匹配对象以获取有关匹配字符串的信息。匹配对象实例也有⼏个很重要的⽅法和属性:
⽅法/属性⽬的
group()返回正则匹配的字符串
⽅法/属性⽬的
start()返回匹配的开始位置
end()返回匹配的结束位置
span()返回包含匹配(start, end)位置的元组
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0,5)
>>> m.span()
(0,5)
group() 返回正则匹配的⼦字符串。start() 和end() 返回匹配的起始和结束索引。span() 在单个元组
中返回开始和结束索引。由于match() ⽅法只检查正则是否在字符串的开头匹配,所以start() 将始终为零。但是,模式的search() ⽅法会扫描字符串,因此在这种情况下匹配可能不会从零开始。
>>>print(p.match('::: message'))
None
>>> m = p.search('::: message');print(m)
<re.Match object; span=(4,11), match='message'>
>>> m.group()
'message'
>>> m.span()
(4,11)
在实际程序中,最常见的样式是在变量中存储匹配对象,然后检查它是否为None
p = repile(...)
m = p.match('string goes here')
if m:
print('Match found: ', m.group())
else:
print('No match')
两种模式⽅法返回模式的所有匹配项。
findall() 返回匹配字符串的列表:
>>> p = repile(r'\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12','11','10']
在这个例⼦中需要r 前缀,使字⾯为原始字符串字⾯,因为普通的“加⼯”字符串字⾯中的转义序列不能被Python 识别为正则表达式,导致DeprecationWarning 并最终产⽣SyntaxError.
findall() 必须先创建整个列表才能返回结果。finditer() ⽅法将⼀个匹配对象的序列返回为⼀个iterator
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable_iterator object >
>>>for match in iterator:
...print(match.span())
...
(0,2)
(22,24)
(29,31)
3.4 模块级别函数
另外,你不必创建模式对象并调⽤其⽅法;re 模块还提供了顶级函数match(),search(),findall(),sub()
等等。这些函数采⽤与相应模式⽅法相同的参数,并将正则字符串作为第⼀个参数添加,并仍然返回None或匹配对象实例。
>>>print(re.match(r'From\s+','Fromage amk'))
None
>>> re.match(r'From\s+','From amk Thu May 14 19:12:10 1998')
<re.Match object; span=(0,5), match='From '>
本质上,这些函数只是为你创建⼀个模式对象,并在其上调⽤适当的⽅法。它们还将编译对象存储在缓存中,因此使⽤相同的未来调⽤将不需要⼀次⼜⼀次地解析该模式。
你是否应该使⽤这些模块级函数,还是应该⾃⼰获取模式并调⽤其⽅法?如果你正在循环中访问正则表达式,预编译它将节省⼀些函数调⽤。在循环之外,由于有内部缓存,没有太⼤区别。
所以在循环之内不建议使⽤模块级别的函数。
3.5 编译标志
编译标志允许你修改正则表达式的⼯作⽅式。标志在re 模块中有两个名称,长名称如IGNORECASE 和⼀个简短的单字母形式,例如I。(如果你熟悉Perl 的模式修饰符,则单字母形式使⽤和其相同的字母;例如,re.VERBOSE 的缩写形式为re.X。)
多个标志可以通过按位或运算来指定它们;例如,re.I | re.M 设置I 和M 标志。
下⾯是可⽤标志表,以及每个标志的更详细说明。
标志意义
ASCII, A使⼏个转义如\w、\b、\s 和\d 匹配仅与具有相应特征属性的ASCII 字符匹配。
DOTALL, S使. 匹配任何字符,包括换⾏符。
IGNORECASE, I进⾏⼤⼩写不敏感匹配。
LOCALE, L进⾏区域设置感知匹配。
MULTILINE, M多⾏匹配,影响^ 和$。
VERBOSE, X(为’ 扩展’)启⽤详细的正则,可以更清晰,更容易理解。
IGNORECASE, I
执⾏不区分⼤⼩写的匹配;字符类和字⾯字符串将通过忽略⼤⼩写来匹配字母。
例如,[A-Z] 也匹配⼩写字母。除⾮使⽤ASCII 标志来禁⽤⾮ASCII 匹配,否则完全Unicode 匹配也有效。
当Unicode模式[a-z] 或[A-Z] 与IGNORECASE 标志结合使⽤时,它们将匹配52 个ASCII 字母和4 个额外的⾮ASCII 字母:’İ’(U+0130,拉丁⼤写字母I,带上⾯的点),’ı’ (U+0131,拉丁⽂⼩写字母⽆点i),’s’(U+017F,拉丁⽂⼩写字母长s) 和’K’(U+212A,开尔⽂符号)。Spam 将匹配’Spam’,‘spam’,‘spAM’或’ſpam’ (后者仅在Unicode 模式下匹配)。此⼩写不考虑当前区域设置;如果你还设置了LOCALE 标志,则将考虑。
LOCALE, L
使\w、\W、\b、\B 和⼤⼩写敏感匹配依赖于当前区域⽽不是Unicode 数据库
区域设置是C 库的⼀个功能,旨在帮助编写考虑到语⾔差异的程序。例如,如果你正在处理编码的法语⽂本,那么你希望能够编写\w+来匹配单词,但\w 只匹配字符类[A-Za-z] 字节模式;它不会匹
配对应于é 或ç 的字节。如果你的系统配置正确并且选择了法语区域设置,某些C 函数将告诉程序对应于é 的字节也应该被视为字母在编译正则表达式时设置LOCALE 标志将导致⽣成的编译对象将这些C 函数⽤于\w;这⽐较慢,但也可以使\w+ 匹配你所期望的法语单词。
在Python 3 中不⿎励使⽤此标志,因为语⾔环境机制⾮常不可靠,它⼀次只处理⼀个“⽂化”,它只适⽤于8 位语⾔环境。默认情况下,Python 3 中已经为Unicode(str)模式启⽤了Unicode 匹配,并且它能够处理不同的区域/语⾔。
MULTILINE, M
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论