第 16 章 正则表达式
16.1 什么是正则表达式
正则表达式(regular expression,常简写为regex、regexp或re),是一种用于匹配和操作文本的强大工具,它是由一系列字符和特殊字符组成的模式,用于描述要匹配的文本模式。正则表达式可以在文本中查找、替换、提取和验证特定的模式。
16.2 re模块
Python的re模块提供了正则表达式匹配操作。
import re
re模块中提供了一些方法用于查找或处理字符串。
16.2.1 search
re.search(pattern, string)
扫描整个 string 查找正则表达式 pattern 产生匹配的第一个位置,并返回相应的 Match。如果字符串中没有与模式匹配的位置则返回 None。
16.2.2 match
re.match(pattern, string)
如果 string 开头的零个或多个字符与正则表达式 pattern 匹配,则返回相应的 Match。如果字符串与模式不匹配则返回 None。
16.2.3 findall
re.findall(pattern, string)
返回 pattern 在 string 中的所有非重叠匹配,以字符串列表或字符串元组列表的形式。对 string 的扫描从左至右,匹配结果按照找到的顺序返回。空匹配也包括在结果中。
16.2.4 sub
re.sub(pattern, repl, string, count=0)
返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。如果样式没有找到,则不加改变地返回 string。
repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,\n 会被转换为一个换行符,\r 会被转换为一个回车符,依此类推。如果 repl 是一个函数,则它会针对每次 pattern 的非重叠出现的情况被调用。 该函数接受单个 Match 参数,并返回替换字符串。
可选参数 count 是要替换的最大次数;count 必须是非负整数。如果省略这个参数或设为 0,所有的匹配都会被替换。
16.2.5 split
re.split(pattern, string, maxsplit=0)
用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。
16.3 表示字符
字符 描述
. 匹配除 \r,\n 之外的任何单个字符。要匹配包括 \r,\n 在内的任何字符,请使用像 (.|\r|\n) 的模式。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\w 匹配包括下划线的任何单词字符。等价于 [A-Za-z0-9_],注意Unicode正则表达式会匹配中文字符。
\W 匹配任何非单词字符。等价于 [^A-Za-z0-9_]。
\s 匹配任何空白字符,包括空格、制表符、换页符等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
[xyz] 匹配所包含的任意一个字符。如 [abc] 可以匹配“plain”中的“a”。特殊字符仅有反斜线 \ 保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符 ^ 如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述;如果出现在首位(或末尾)则仅作为普通字符。右方括号应转义出现,也可以作为首位字符出现。
[^xyz] 匹配未列出的任意字符。
[a-z] 字符范围。匹配在Unicode编码表指定范围内的任意字符。
例如,[a-z]可以匹配“a”到“z”范围内的任意小写字母字符。
16.4 表示数量
字符 描述
text = “abcdef123456”
print(re.search(r"\w+“, text))
print(re.search(”\w+", text)) # SyntaxWarning: invalid escape sequence ‘\w’
不使用原始字符串虽然也能运行,但是会有语法警告。
16.8 案例
16.8.1 匹配电话号码
import re
test = [
“13812345678”, # 合法
“11456817239”, # 非法
“19912345678”, # 合法
“17138412356”, # 合法
“1234567890”, # 非法
“14752345673”, # 合法
“1800123456”, # 非法
]
pattern = r"^1[345789]\d{9}$"
for i in test:
print(f"{i:20}{“合法” if re.match(pattern, i) else “非法”}")
16.8.2 匹配邮箱
import re
test = [
“[email protected]”,
“[email protected]”,
“[email protected]”,
“@missingusername.com”,
“[email protected]”,
]
pattern = r"[\w!# %&'*+-/=?^`{|}~.]+@[\w!# %&'*±/=?^`{|}~.]+.[a-zA-Z]{2,}$"
for i in test:
print(f"{i:40}{“合法” if re.match(pattern, i) else “非法”}")
16.8.3 匹配0-255之间的数字
import re
test = [“0”, “9”, “50”, “100”, “199”, “200”, “255”, “256”, “-1”, “01”, “001”]
pattern = r"^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])$"
for num in test:
print(f"{num:5} {“合法” if re.match(pattern, num) else “非法”}")
16.8.4 从标签中获取网址
import re
test = “”"
"""pattern = r"href=“(.+?)”"
for i in re.findall(pattern, test):
print(i)
16.8.5 替换文本中的所有数字为对应的词
import re
test = “I have 2 apples and 3 oranges.”
num_map = {“1”: “one”, “2”: “two”, “3”: “three”, “4”: “four”, “5”: “five”}
print(re.sub(r"\d", lambda x: num_map[x.group(0)], test)) # I have two apples and three oranges.