Python 正则学习

参考官方文档

正则表达式 Regular Expression 的主要功能是从字符串(string)中通过特定的模式,搜索希望找到的内容。

1. re

Python 中可以使用包 re 来处理正则表达式。

下面是一个简单的应用,目的是找到字符串中的数字:

import re

m = re.search("[0-9]", "ab5cd4ef")
print(m.group())

re.search() 接收两个参数,第一个参数 [0-9] 就是我们所说的正则表达式,它告诉 Python,听着,我想从字符串中找从 0 到 9 的任意一个数字字符

re.search() 如果从第二个参数中找到符合要求的子字符串,就返回一个对象 m,你可以通过 m.group() 的方法查看搜索到的结果。如果没有找到符合要求的字符,则 re.search() 会返回 None

除了 search() 方法外,re 包还提供了其他搜索方法,它们的功能有所差别:

# 搜索整个字符串,直到发现符合的子字符串,如果没有发现返回 None
m = re.search(pattern, string)
# 从头开始检查字符串是否符合正则表达式。
# 必须从字符串的第一个字符开始就相符
m = re.match(pattern, string)

我们可以从这两个函数中选择一个进行搜索。上面的例子中,如果使用 re.match() 的话,则会得到 None,因为字符串的起始为 a,不符合 [0-9] 的要求。再一次,我们可以使用 m.group() 来查看找到的字符串。

我们还可以在搜索之后将搜索到的子字符串进行替换。下面的 sub() 利用正则 pattern 在字符串 string 中进行搜索。对于搜索到的字符串,用另一个字符串 replacement 进行替换。函数将返回替换后的字符串:

str = re.sub(pattern, replacement, string)

此外,常用的方法还有

# 根据正则表达式分割字符串,将分割后的所有子字符串
# 放在一个列表(list)中返回
re.split()
# 根据正则表达式搜索字符串,将所有符合条件的子字符串
# 放在一个列表(list)中返回
re.findall()

如何写正则表达式

正则表达式的功能其实非常强大,关键在于如何写出有效的正则表达式。

我们先看正则表达式的常用语法。

正则表达式用某些符号代表单个字符:

  • .

    任意的一个字符

  • a|b

    字符 a 或字符 b

  • [afg]

    a 或者 f 或者 g 中的一个字符

  • [0-4]

    0-4 范围内的一个字符

  • [a-f]

    a-f 范围内的一个字符

  • [^m]

    不是 m 的一个字符

  • \s

    一个空格

  • \S

    一个非空格

  • \d

    一个数字,相当于 [0-9]

  • \D

    一个非数字,相当于 [^0-9]

  • \w

    任何语言单词的一部分的字符,以及数字和下划线

  • \W

    匹配任何不是单词字符的字符

正则表达式还可以用某些符号来表示某种形式的重复,这些符号紧跟在单个字符之后,就表示多个这样类似的字符

  • *

    重复超过 0 次或更多次,尽量多的匹配字符串。

  • +

    重复 1 次或超过 1

  • ?

    重复 0 次或 1

  • {m}

    重复 m 次。比如,a{4} 相当于 aaaa,再比如,[1-3]{2} 相当于 [1-3][1-3]

  • {m, n}

    重复 mn 次。比如说 a{2, 5} 表示 a 重复 25 次。小于 m 次的重复,或者大于 n 次的重复都不符合条件

  • *?, +?, ??

    *, +,和 ? 修饰符都是 贪婪 的;它们在字符串进行尽可能多的匹配。有时候并不需要这种行为。

    如果正则式 <.*> 希望找到 <a> b <c>,它将会匹配整个字符串,而不仅是 <a>

    在修饰符之后添加 ? 将使样式以 非贪婪 方式进行匹配;尽量的字符将会被匹配。

    使用正则式 <.*?> 将会仅仅匹配 <a>

  • {m,n}?

    非贪婪模式,只匹配尽量少的字符次数。比如,对于 aaaaaaa{3,5} 匹配 5 个 a,而 a{3,5}? 只匹配 3 个 a

  • |

    或者,A|BAB,绝不贪婪

下面是重复符号的例子:

正则表达 相符的字符串举例 不相符字符串举例
[0-9]{3,5} "9678" "12" "1234567"
a?b "b" "ab" "cb" "ac"
a+b "aaaaab" "b"

最后,还有位置相关的符号:

  • ^

    字符串的起始位置

  • $

    字符串的结尾位置

下面是位置符号的一些例子:

正则表达 相符的字符串举例 不相符的字符串
^ab.*c$ abeec cabeec

信息提取

有的时候,我们想在搜索的同时,对结果进一步提炼。比如说,我们从下面一个字符串中提取信息:

s = "abcd_output_1994_abcd_1912_abcd"

如果我们把正则表达式写成:

"output_\d{4}"

那么用 search() 方法可以找到 output_1994 。但如果我们想进一步提取出 1994 本身,则可以在正则表达式上给目标加上括号:

output_(\d{4})

括号 () 包围了一个小的正则表达式 \d{4}。这个小的正则表达式能从结果中进一步筛选信息,即四位的阿拉伯数字。用括号 () 圈起来的正则表达式的一部分,称为群(group)。一个正则表达式中可以有多个群。

我们可以 group(number) 的方法来查询群。需要注意的是,group(0) 是整个正则表达的搜索结果。group(1) 是第一个群,以此类推:

import re
m = re.search(r"output_(\d{4})", "output_1986.txt")
print(m.group(1)) # 将找到4个数字组成的1986

我们还可以将群命名,以便更好地使用 group 查询:

import re
m = re.search(r"output_(?P<year>\d{4})", "output_1986.txt") #(?P<name>...) 为group命名
print(m.group("year")) # 打印1986

上面的 (?P<year>…) 括住了一个群,并把它命名为 year。用这种方式来产生群,就可以通过 year 这个键来提取结果。

1. 正则表达式对象

以上都是直接通过正则表达式来进行操作,很多时候为了更方便应用正则表达式,会将正则表达式的样式编译为一个正则表达式对象(正则对象),可以用于匹配,通过这个对象的方法进行操作,在特定情况下使正则应用更加高效。

pattern = re.compile(r"output_(\d{4})")
pattern.search("output_1986.txt")
pattern.search("output_1986.txt").group(1)

2. 多行搜索

re.findall(r"^wo.*", "hello\nworld\nworld hello")
re.findall(r"^wo.*", "hello\nworld\nworld hello", flags=re.M)

3. 忽略大小写

re.findall(r"^wo.*", "hello\nworld\nWorld hello", flags=re.M)
re.findall(r"^wo.*", "hello\nworld\nWorld hello", flags=(re.M + re.I))
© 2022 刘士. All rights reserved.

结果匹配 ""

    没有匹配的结果 ""