正则表达式(称为RE,或正则,或正则表达式模式)本质上是嵌入在Python中的一种微小的、高度专业化的编程语言,可通过 re
模块获得。
简单模式
正则表达式用于对字符串进行操作,因此我们将从最常见的任务开始:匹配字符
匹配字符:匹配不同的字符集合是正则表达式可以做的第一件事
元字符是 [
和 ]
[abc],[a-c],[0-9],[abc作为元字符在中括号内失效,[^5] 匹配非'5'的字符,[5^]
将匹配 '5'
或 '^'
元字符是反斜杠,\
反斜杠来移除它们的特殊含义:\[
或 \\
,
以 '\'
开头的特殊序列表示通常有用的预定义字符集
-
\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_]
。
元字符是 .
它匹配除换行符之外的任何内容,并且有一个可选模式( re.DOTALL
)甚至可以匹配换行符
重复:指定正则的某些部分必须重复一定次数
元字符是 *
一个逐步的例子将使这更加明显。 让我们考虑表达式 a[bcd]*b
。 这个正则匹配字母 'a'
,类 [bcd]
中的零或多个字母,最后以 'b'
结尾。 现在想象一下这个正则与字符串 'abcbd'
匹配。
步骤 | 匹配 | 说明 |
---|---|---|
1 | a |
正则中的 a 匹配。 |
2 | abcbd |
引擎尽可能多地匹配 [bcd]* ,直到字符串结束。 |
3 | 失败 | 引擎尝试匹配 b ,但是当前位置位于字符串结束,所以匹配失败。 |
4 | abcb |
回退一次,[bcd]* 少匹配一个字符。 |
5 | 失败 | 再次尝试匹配 b , 但是当前位置是最后一个字符 'd' 。 |
6 | abc |
再次回退,所以 [bcd]* 只匹配 bc 。 |
6 | abcb |
再试一次 b 。 这次当前位置的字符是 'b' ,所以它成功了。 |
元字符是 +
ca+t
将匹配 'cat'
(1 个 'a'
),'caaat'
(3 个 'a'
),但不会匹配 'ct'
重复限定符。 问号字符 ?
匹配一次或零次
home-?brew
匹配 'homebrew'
或 'home-brew'
重复限定符是 {m,n}
a/{1,3}b
将匹配 'a/b'
,'a//b'
和 'a///b'
。 它不匹配没有斜线的 'ab'
,或者有四个的 'a////b'
, {0,}
与 *
相同, {1,}
相当于 +
, {0,1}
和 ?
相同。 最好使用 *
, +
或 ?
,只要因为它们更短更容易阅读。
使用正则表达式
re
模块提供了正则表达式引擎的接口,允许你将正则编译为对象,然后用它们进行匹配
编译正则表达式
正则表达式被编译成模式对象,模式对象具有各种操作的方法,例如搜索模式匹配或执行字符串替换
p = re.compile('ab*')
re.compile()
也接受一个可选的 flags 参数,用于启用各种特殊功能和语法变体, p = re.compile('ab*', re.IGNORECASE)
正则作为字符串传递给 re.compile()
,将正则放在字符串中可以使 Python 语言更简单,但有一个缺点:反斜杠灾难。解决方案 r"\n"
是一个包含 '\'
和 'n'
的双字符字符串,而 "\n"
是一个包含换行符的单字符字符串。
应用匹配
一旦你有一个表示编译正则表达式的对象,你用它做什么? 模式对象有几种方法和属性。
方法 / 属性 | 目的 |
---|---|
match() |
确定正则是否从字符串的开头匹配。 |
search() |
扫描字符串,查找此正则匹配的任何位置。 |
findall() |
找到正则匹配的所有子字符串,并将它们作为列表返回。 |
finditer() |
找到正则匹配的所有子字符串,并将它们返回为一个 iterator。 |
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
re.compile('[a-z]+')
>>> p.match("")
>>> print(p.match(""))
None
>>> m = p.match('tempo')
>>> m
<re.Match object; span=(0, 5), match='tempo'>
现在你可以检查 匹配对象 以获取有关匹配字符串的信息。 匹配对象实例也有几个方法和属性;最重要的是:
方法 / 属性 | 目的 |
---|---|
group() |
返回正则匹配的字符串 |
start() |
返回匹配的开始位置 |
end() |
返回匹配的结束位置 |
span() |
返回包含匹配 (start, end) 位置的元组 |
尝试这些方法很快就会清楚它们的含义:
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 = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print('Match found: ', m.group())
else:
print('No match')
两种模式方法返回模式的所有匹配项。 findall()
返回匹配字符串的列表:
>>>
>>> p = re.compile(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 at 0x...>
>>> for match in iterator:
... print(match.span())
...
(0, 2)
(22, 24)
(29, 31)
模块级别函
>>> 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 '>
编译标志
这是一个可用标志表,以及每个标志的更详细说明。
Flag | 含义 |
---|---|
ASCII , A
|
使几个转义如 \w 、\b 、\s 和 \d 匹配仅与具有相应特征属性的 ASCII 字符匹配。 |
DOTALL , S
|
使 . 匹配任何字符,包括换行符。 |
IGNORECASE , I
|
进行大小写不敏感匹配。 |
LOCALE , L
|
进行区域设置感知匹配。 |
MULTILINE , M
|
多行匹配,影响 ^ 和 $ 。 |
VERBOSE , X (为 '扩展') |
启用详细的正则,可以更清晰,更容易理解。 |
re.I | re.M
设置 I
和 M
标志
这里的正则使用 re.VERBOSE
;看看阅读有多容易?: charref = re.compile(r""" &[#] # Start of a numeric entity reference ( 0[0-7]+ # Octal form | [0-9]+ # Decimal form | x[0-9a-fA-F]+ # Hexadecimal form ) ; # Trailing semicolon """, re.VERBOSE)
如果没有详细设置,正则将如下所示: charref = re.compile("&#(0[0-7]+" "|[0-9]+" "|x[0-9a-fA-F]+);")
更多元字符
Crow|Servo
将匹配 'Crow'
或 'Servo'
,而不是 'Cro'
、'w'
或 'S'
和 'ervo'
print(re.search('^From', 'From Here to Eternity')) <re.Match object; span=(0, 4), match='From'> print(re.search('^From', 'Reciting From Memory')) None `
print(re.search('}$', '{block}')) <re.Match object; span=(6, 7), match='}'> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) <re.Match object; span=(6, 7), match='}'> `
网友评论