>>> from env_helper import info; info()
页面更新时间: 2024-03-29 09:21:35
运行环境:
Linux发行版本: Debian GNU/Linux 12 (bookworm)
操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
Python版本: 3.11.2
1.4. 正则表达式字符详解¶
1.4.1. 字符分类¶
在前面电话号码正则表达式的例子中, 你知道 \d
可以代表任何数字。
也就是说, \d
是正则表达式(0|1|2|3|4|5|6|7|8|9)
的缩写。
有许多这样的“缩写字符分类”,如表7-1所示。
常用字符分类的缩写代码
缩写字符分类 | 表示
\d
| 0到9的任何数字\D
| 除0到9的数字以外的任何字符\w
| 任何字母,数字或下划线字符,可以认为是匹配,单词,字符,\W
| 除字母,数字和下划线以外的任何字符\s
| 空格,制表符或换行符,可以认为是匹配,空白 ,字符\S
| 除空格,制表符和换行符以外的任何字符,
字符分类对于缩短正则表达式很有用。 字符分类[0-5]只匹配数字0到5,
这比输入(0|1|2|3|4|5)
要短很多。
例如,在交互式环境中输入以下代码:
>>> import re
>>> xmasRegex = re.compile(r'\d+\s\w+')
>>> xmasRegex.findall('12 drummers, 11 pipers, 10 lords, 9 ladies, 8 maids, 7 swans, 6 geese, 5 rings, 4 birds, 3 hens, 2 doves, 1 partridge')
['12 drummers',
'11 pipers',
'10 lords',
'9 ladies',
'8 maids',
'7 swans',
'6 geese',
'5 rings',
'4 birds',
'3 hens',
'2 doves',
'1 partridge']
正则表达式 \d+\s\w+
匹配的文本有 一个或多个数字 (\d+)
,接下来是一个空白字符(\s)
,
接下来是一个或多个字母/数字/下划线字符(\w+)
。
findall()
方法将返回所有匹配该正则表达式的字符串, 放在一个列表中。
1.4.2. 建立自己的字符分类¶
有时候你想匹配一组字符,但缩写的字符分类 ( \d
、\w
、\s
等)太宽泛。 你可以用方括号定义自己的字符分类。例如,
字符分类[aeiouAEIOU]
将匹配所有元音字符,
不论大小写。在交互式环境中输入以下代码:
>>> import re
>>> vowelRegex = re.compile(r'[aeiouAEIOU]')
>>> vowelRegex.findall('RoboCop eats baby food. BABY FOOD.')
['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O']
也可以使用短横表示字母或数字的范围。例如, 字符分类[a-zA-ZO-9]将匹配所有小写字母、 大写字母和数字。
请注意,在方括号内,普通的正则表达式符号不会被解释。
这意味着,你不需要前面加上倒斜杠转义.
、
*
、?
或()
字符。例如, 字符分类将匹配数字0到5和一个
句点。你不需要将它写成[0-5\.]
。
通过在字符分类的左方括号后加上一个插入字符(^)
,
就可以得到“非字符类”。 非字符类将匹配不在这个字符类中的所有字符。
例如,在交互式环境中输入以下代码:
>>> import re
>>> vowelRegex = re.compile(r'[^aeiouAEIOU]')
>>> print(vowelRegex.findall('RoboCop eats baby food. BABY FOOD.'))
['R', 'b', 'C', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
1.4.3. 插入字符和美元字符¶
可以在正则表达式的开始处使用插入符号(^)
,表明匹配必须发生在被查找文本开始处。类似地,可以再正则表达式的末尾加上美元符号($)
,表示该字符串必须以这个正则表达式的模式结束。可以同时使用
^
和$
,表明整个字符串必须匹配该模式,也就是说,只匹配该字符串的某个子集是不够的。
例如,正则表达式 r'^Hello'
匹配以 'Hello'
开始的字符串。
在交互式环境中输入以下代码:
>>> import re
>>> beginsWithHello = re.compile(r'^Hello')
>>> beginsWithHello.search('Hello world!')
<re.Match object; span=(0, 5), match='Hello'>
>>> beginsWithHello.search('He said hello.') == None
True
正则表达式 r'\d$'
匹配以数字0到9结束的字符串。
在交互式环境中输入以下代码:
>>> endsWithNumber = re.compile(r'\d$')
>>> endsWithNumber.search('Your number is 42')
<re.Match object; span=(16, 17), match='2'>
>>> endsWithNumber.search('Your number is forty two.') == None
True
正则表达式 r'^\d+$'
匹配从开始到结束都是数字的字符串。
在交互式环境中输入以下代码:
>>> wholeStringlsNum = re.compile(r'^\d+$')
>>> wholeStringlsNum.search('1234567890')
<re.Match object; span=(0, 10), match='1234567890'>
>>> wholeStringlsNum.search('12345xyz67890') == None
True
>>> wholeStringlsNum.search('12 34567890') == None
True
前面交互式脚本例子中的最后两次 search()
调用表明, 如果使用了 a
和 $
, 那么整个字符串必须匹配该正则表达式。
我总是会混淆这两个符号的含义, 所以我使用助记法 “Carrots cost dollars”, 提醒我插入符号在前面,美元符号在后面。
1.4.4. 通配字符¶
在正则表达式中,.
(句点)字符称为“通配符”。
它匹配除了换行之外的所有字符。 例如,在交互式环境中输入以下代码:
>>> import re
>>> atRegex = re.compile(r'.at')
>>> atRegex.findall('The cat in the hat sat on the flat mat.')
['cat', 'hat', 'sat', 'lat', 'mat']
要记住,句点字符只匹配一个字符,这就是为什么在前面的例子中, 对于文本
flat
,只匹配 lat
。要匹配真正的句点,
就是用倒斜杠转义:\.
。
1.4.5. 用点-星匹配所有字符¶
有时候想要匹配所有字符串。例如, 假定想要匹配字符串 'FirstName:'
,
接下来是任意文本,接下来是 'LastName:'
,
然后又是任意文本。可以用点-星(.*)表不“任意文本”。
回忆一下,句点字符表示“除换行外所有单个字符”,
星号字符表示“前面字符出现零次或多次”。
在交互式环境中输入以下代码:
>>> nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)')
>>> mo = nameRegex.search('First Name: A1 Last Name: Sweigart')
>>> mo.group(1)
'A1'
>>> mo.group(2)
'Sweigart'
点-星使用“贪心”模式:它总是匹配尽可能多的文本。 要用“非贪心”模式匹配所有文本,就使用点-星和问号。 像和大括号一起使用时那样,问号告诉Python用非贪心模式匹配。 在交互式环境中输入以下代码, 看看贪心模式和非贪心模式的区别:
>>> nongreedyRegex = re.compile(r'<.*?>')
>>> mo = nongreedyRegex.search('<To serve man> for dinner.>')
>>> mo.group()
'<To serve man>'
>>> greedyRegex = re.compile(r'<.*>')
>>> mo = greedyRegex.search('<To serve man> for dinner.>')
>>> mo.group()
'<To serve man> for dinner.>'
两个正则表达式都可以翻译成“匹配一个左尖括号,接下来是任意字符,接下来是一个右尖括号”。但是字符串
'<To serve man> for dinner.>'
对右肩括号有两种可能的匹配。在非贪心的正则表达式中,Python匹配最短可能的字符串:'<To serve man>'
。在贪心版本中,Python匹配最长可能的字符串:'<To serve man> for dinner>'
。
1.4.6. 用句点字符匹配换行¶
点-星将匹配除换行外的所有字符。 通过传入 re.DOTALL
作为
re.compile()
的
第二个参数,可以让句点字符匹配所有字符,包括换行字符。
在交互式环境中输入以下代码:
>>> noNewlineRegex =re.compile('.*')
>>> noNewlineRegex.search('Servethe public trust.\nProtect the innocent.\nUphold the law.').group()
'Servethe public trust.'
>>> newlineRegex =re.compile('.*', re.DOTALL)
>>> newlineRegex.search('Serve thepublic trust.\nProtect the innocent.\nUphold the law.').group()
'Serve thepublic trust.nProtect the innocent.nUphold the law.'
正则表达式 noNewlineRegex
在创建时没有向 re.compile()
传入
re.DOTALL
,它将匹配所有字符,直到第一个换行字符。但是,newlineRegex
在创建时向 re.compile()
传入了 re.DOTALL
,它将匹配所有字符。这就是为什么
newlineRegex.search()
调用匹配完整的字符串,包括其中的换行字符。