本章 Python 教程的目的是对正则表达式进行详细的描述性介绍。本介绍将解释正则表达式的理论方面,并将向您展示如何在 Python 脚本中使用它们。
术语“正则表达式”,有时也称为 regex 或 regexp,起源于理论计算机科学。在理论计算机科学中,它们用于定义具有某些特征的语族,即所谓的正则语言。每个正则表达式都存在一个接受由正则表达式定义的语言的有限状态机 (FSM)。您可以在我们的网站上找到用 Python实现的有限状态机。
正则表达式在编程语言中用于过滤文本或文本字符串。可以检查文本或字符串是否与正则表达式匹配。正则表达式的一大优点:正则表达式的语法对于所有编程和脚本语言都是相同的,例如 Python、Perl、Java、SED、AWK 甚至 X#。
第一个包含使用正则表达式功能的程序是 Unix 工具 ed(编辑器)、流编辑器 sed 和过滤器 grep。
操作系统中还有另一种机制,不应将其误认为正则表达式。通配符,也称为通配符,在语法上与正则表达式非常相似。但是,语义差异很大。Globbing 在许多命令行 shell 中都为人所知,例如 Bourne shell、Bash shell 甚至 DOS。例如,在 Bash 中,命令“ls .txt”列出了所有以 .txt 结尾的文件(甚至目录);在正则表达式符号中“ .txt”没有意义,它必须写成“.*.txt”
介绍
当我们介绍顺序数据类型时,我们了解了“in”运算符。我们在下面的例子中检查,如果字符串“easyly”是字符串“Regular expressions easy Explain!”的子字符串:
s = "正则表达式很容易解释!"
“容易” 在 小号
输出:
真的
我们用下图一步一步地展示了这个匹配是如何执行的: 我们检查字符串 sub = "abc"
包含在字符串 s = "xaababcbcd" 中
顺便说一下,字符串 sub = "abc" 可以看作是一个正则表达式,只是一个非常简单的表达式。
首先,我们检查两个字符串的第一个位置是否匹配,即 s[0] == sub[0]。这在我们的例子中是不满足的。我们用红色标记这一事实:
然后我们检查,如果 s[1:4] == sub。换句话说,我们必须首先检查 sub[0] 是否等于 s[1]。这是真的,我们用绿色标记它。然后,我们必须比较下一个位置。s[2] 不等于 sub[1],因此我们不必进一步处理 sub 和 s 的下一个位置:
现在我们必须检查 s[2:5] 和 sub 是否相等。前两个位置相等但第三个位置不相等:
下面的步骤应该很清楚了,不做任何解释:
最后,我们与 s[4:7] == sub 完全匹配:
一个简单的正则表达式
正如我们在上一节中已经提到的,我们可以将介绍中的变量“sub”视为一个非常简单的正则表达式。如果你想在 Python 中使用正则表达式,你必须导入 re 模块,它提供了处理正则表达式的方法和函数。
在 Python 中表示正则表达式
在其他语言中,您可能习惯于在斜杠“/”中表示正则表达式,例如,这是 Perl、SED 或 AWK 处理它们的方式。在 Python 中没有特殊符号。正则表达式表示为普通字符串。
但是这种方便带来了一个小问题:反斜杠是正则表达式中使用的特殊字符,但也用作字符串中的转义字符。这意味着 Python 将首先评估字符串的每个反斜杠,然后 - 没有必要的反斜杠 - 它将被用作正则表达式。防止这种情况的一种方法是将每个反斜杠都写为“\”,并以此方式保留它以用于正则表达式的评估。这会导致非常笨拙的表达。例如,正则表达式中的反斜杠必须写成双反斜杠,因为反斜杠在正则表达式中用作转义字符。因此,必须引用它。这同样适用于 Python 字符串。反斜杠必须用反斜杠引用。因此,匹配 Windows 路径的正则表达式“
克服这个问题的最好方法是将正则表达式标记为原始字符串。我们的 Windows 路径示例的解决方案看起来像这样作为一个原始字符串:
r"C:\\程序"
让我们再看一个例子,对于习惯使用通配符的人来说,这可能会非常令人不安:
r"^a.*\.html$"
我们前面示例的正则表达式匹配所有以“a”开头并以“.html”结尾的文件名(字符串)。我们将在下面的章节中详细解释上面例子的结构。
正则表达式的语法
r"猫"
是一个正则表达式,虽然非常简单,没有任何元字符。我们的 RE
r"猫"
例如,匹配以下字符串:“猫和老鼠不能成为朋友。”
有趣的是,前面的示例已经显示了一个“最喜欢”的错误示例,不仅初学者和新手经常犯,而且正则表达式的高级用户也经常犯这种错误。这个例子的想法是匹配包含单词“cat”的字符串。我们在这方面取得了成功,但不幸的是,我们也匹配了很多其他词。如果我们在一个字符串中匹配“cats”可能仍然没问题,但是所有包含这个字符序列“cat”的单词呢?我们匹配诸如“教育”、“交流”、“伪造”、“后果”、“牛”等词。这是一种“过度匹配”的情况,即我们收到了积极的结果,根据我们要解决的问题,这些结果是错误的。
我们已经在上图中说明了这个问题。深绿色圆圈 C 对应于我们想要识别的“对象”集。但是我们匹配集合 O(蓝色圆圈)的所有元素。C 是 O 的子集。此图中的集合 U(浅绿色圆圈)是 C 的子集。U 是“欠匹配”的情况,即如果正则表达式未匹配所有预期字符串。如果我们尝试修复之前的 RE,使其不会创建过度匹配,我们可能会尝试表达式
r“猫”
. 这些空白阻止了上面提到的“教育”、“伪造”和“分支”等词的匹配,但我们又犯了另一个错误。字符串“名叫奥斯卡的猫爬上了屋顶。”怎么样?问题是我们不希望有一个逗号,而只是在“cat”这个词周围有一个空格。
在我们继续描述正则表达式的语法之前,我们想解释一下如何在 Python 中使用它们:
导入 re
x = re 。search ( "cat" , "猫和老鼠不能成为朋友。" )
打印( x )
输出:
<re.Match 对象;跨度=(2, 5),匹配=“猫”>
x = 重新。搜索(“牛” , “猫和老鼠不能成为朋友。” )
打印(x )
输出:
没有任何
在前面的示例中,我们必须导入模块 re 才能使用正则表达式。然后我们使用了 re 模块中的搜索方法。这很可能是本模块中最重要和最常用的方法。re.search(expr,s) 检查字符串 s 中是否出现与正则表达式 expr 匹配的子字符串。将返回满足此条件的第一个子字符串(从左起)。如果匹配是可能的,我们就会得到一个所谓的匹配对象作为结果,否则该值将为 None。这种方法已经足以在 Python 程序中以基本方式使用正则表达式。我们可以在条件语句中使用它:如果正则表达式匹配,我们将返回一个 SRE 对象,该对象被视为 True 值,如果不匹配,则返回值 None 被视为 False:
如果 重新。search ( "cat" , "猫和老鼠不能成为朋友。" ):
print ( "找到某种猫:-)" )
else :
print ( "没有找到猫:-)" )
输出:
发现了某种猫:-)
如果 重新。search ( "cow" , "A cat and a rat 不能成为朋友。" ):
print ( "Cats and Rats and a cow." )
else :
print ( "No cow around." )
输出:
周围没有牛。
任何字符
让我们假设我们对前面的例子没有兴趣识别单词 cat,而是所有以“at”结尾的三个字母的单词。正则表达式的语法提供了一个元字符“.”,它用作“任何字符”的占位符。我们示例的正则表达式可以这样写: r" .at " 这个正则匹配三个字母的单词,由空格隔开,以“at”结尾。现在我们得到诸如“rat”、“cat”、“bat”、“eat”、“sat”等许多词。
但是,如果文本包含诸如“@at”或“3at”之类的“单词”怎么办?这些词也匹配,这意味着我们再次导致过度匹配。我们将在下一节中学习解决方案。
字符类
方括号“[”和“]”用于包含字符类。[xyz] 表示例如“x”、“y”或“z”。让我们看一个更实际的例子:
r"M[ae][iy]er"
这是一个正则表达式,它匹配德语中很常见的姓氏。具有相同发音和四种不同拼写的名称:Maier、Mayer、Meier、Meyer 识别此表达式的有限状态自动机可以这样构建:
简化了有限状态机 (FSM) 的图形以保持设计简单。起始节点中应该有一个指向它自己的箭头,即如果处理了大写“M”以外的字符,则机器应保持在起始状态。此外,应该有一个箭头从除最终节点(绿色节点)之外的所有节点指向起始节点,除非预期的字母已被处理。例如,如果机器处于状态 Ma,在处理了“M”和“a”之后,如果可以读取除“i”或“y”之外的任何字符,则机器必须返回到状态“开始”。对这个 FSM 有问题的人不必担心,因为它不是本章其余部分的先决条件。
我们经常需要在更大的字符类之间进行选择,而不是在两个字符之间进行选择。我们可能需要例如“a”和“e”之间或“0”和“5”之间的一类字母。为了管理这样的字符类,正则表达式的语法提供了一个元字符“-”。[ae] [abcde] 或 [0-5] 的简化写法表示 [012345]。
如果我们必须将诸如“任何大写字母”之类的表达式转换为正则表达式,则优势是显而易见的,甚至更令人印象深刻。因此,我们可以写 [AZ],而不是 [ABCDEFGHIJKLMNOPQRSTUVWXYZ]。如果这不能令人信服:为字符类“任何小写或大写字母”写一个表达式[A-Za-z]
还有更多关于破折号的东西,我们用来标记字符类的开始和结束。破折号只有在方括号内使用时才具有特殊含义,并且在这种情况下,仅当它不直接位于开头之后或右括号之前。所以表达式 [-az] 只是在“-”、“a”和“z”三个字符之间进行选择,而没有其他字符。[az-] 也是如此。
练习:[-az] 描述了什么字符类?
答案 字符“-”和所有字符“a”、“b”、“c”一直到“z”。
方括号内唯一的其他特殊字符(字符类选择)是插入符号“^”。如果它直接在开方括号之后使用,则会否定选择。[^0-9] 表示选择“除数字外的任何字符”。方括号内插入符号的位置至关重要。如果它没有定位为左方括号后面的第一个字符,则它没有特殊含义。[^abc] 表示“a”、“b”或“c”以外的任何内容 [a^bc] 表示“a”、“b”、“c”或“^”
Python 中的实践练习
在我们