PYTHON-使用正则表达式进行模式匹配
目录
- Python 正则表达式
- Finding Patterns of Text Without Regular Expressions
- Finding Patterns of Text with Regular Expressions
- Creating Regex Objects
- Matching Regex Objects
- Review of Regular Expression Matching
- More Pattern Matching with Regular Expressions
- Grouping with Parentheses
- Matching Multiple Groups with the Pipe
- Optional Matching with the Question Mark
- Matching Zero or More with the Star
- Matching One or More with the Plus
- Matching Specific Repetitions with Braces
- Greedy and Non-greedy Matching
- The findall() Method
- Character Classes
- Making Your Own Character Classes
- The Caret and Dollar Sign Characters
- The Wildcard Character
- Matching Everything with Dot-Star
- Matching Newlines with the Dot Character
- Review of Regex Symbols
- Case-Insensitive Matching
- Substituting Strings with the sub() Method
- Managing Complex Regexes
- Combining re.IGNORECASE, re.DOTALL, and re.VERBOSE
- Project: Phone Number and Email Address Extractor
- Step 1: Create a Regex for Phone Numbers
- Step 2: Create a Regex for Email Addresses
- Step 3: Find All Matches in the Clipboard Text
- Step 4: Join the Matches into a String for the Clipboard
Python 正则表达式
您可能熟悉通过按 CTRL-F 并输入您要查找的单词来搜索文本。正则表达式更进一步:它们允许您指定要搜索的文本模式。您可能不知道企业的确切电话号码,但如果您居住在美国或加拿大,您知道它将是三位数字,后跟连字符,然后是四位数字(以及可选的三位数区号,位于开始)。作为人类,您看到电话号码时就是这样知道的:415-555-1234 是电话号码,但 4,155,551,234 不是。
我们每天还识别各种其他文本模式:电子邮件地址中间有@符号,美国社会安全号码有九个数字和两个连字符,网站URL通常有句号和正斜杠,新闻标题使用标题大小写,社交媒体主题标签以 # 开头且不包含空格等。
正则表达式很有用,但很少有非程序员了解它们,尽管大多数现代文本编辑器和文字处理程序(例如 Microsoft Word 或 OpenOffice)都具有可以基于正则表达式进行搜索的查找和查找和替换功能。正则表达式不仅对于软件用户而且对于程序员来说都可以节省大量时间。事实上,科技作家科里·多克托罗 (Cory Doctorow) 认为,我们甚至应该在编程之前就学习正则表达式:
知道[正则表达式]意味着用 3 步解决问题和用 3,000 步解决问题之间的区别。当你是一个书呆子时,你会忘记,你通过几次按键就能解决的问题可能需要其他人花费数天的乏味且容易出错的工作才能完成。
在本章中,您将首先编写一个程序来查找文本模式而不使用正则表达式,然后了解如何使用正则表达式来使代码不那么臃肿。我将向您展示与正则表达式的基本匹配,然后继续介绍一些更强大的功能,例如字符串替换和创建您自己的字符类。最后,在本章末尾,您将编写一个程序,可以自动从文本块中提取电话号码和电子邮件地址。
Finding Patterns of Text Without Regular Expressions
假设您想在字符串中查找美国电话号码。如果您是美国人,您就知道这种模式:三个数字、一个连字符、三个数字、一个连字符和四个数字。示例如下:415-555-4242。
让我们使用名为 isPhoneNumber() 的函数来检查字符串是否与此模式匹配,返回 True 或 False。打开一个新的文件编辑器选项卡并输入以下代码;然后将文件另存为 isPhoneNumber.py:
def isPhoneNumber(text):➊ if len(text) != 12:return Falsefor i in range(0, 3):➋ if not text[i].isdecimal():return False➌ if text[3] != '-':return Falsefor i in range(4, 7):➍ if not text[i].isdecimal():return False➎ if text[7] != '-':return Falsefor i in range(8, 12):➏ if not text[i].isdecimal():return False➐ return True
print('Is 415-555-4242 a phone number?')
print(isPhoneNumber('415-555-4242'))
print('Is Moshi moshi a phone number?')
print(isPhoneNumber('Moshi moshi'))
当这个程序运行时,输出如下所示:
isPhoneNumber()
函数的代码会执行多次检查以查看文本中的字符串是否为有效的电话号码。如果其中任何检查失败,该函数将返回 False。首先,代码检查字符串是否正好是 12 个字符 ➊。然后它检查区号(即文本中的前三个字符)是否仅由数字字符 ➋ 组成。该函数的其余部分检查字符串是否遵循电话号码的模式:该号码必须在区号 ➌ 之后包含第一个连字符,再添加三个数字字符 ➍,然后再添加一个连字符 ➎,最后再添加四个数字 ➏。如果程序执行成功通过了所有检查,则返回 True ➐。
使用参数“415-555-4242”调用 isPhoneNumber()
将返回 True
。使用 ‘Moshi moshi’ 调用 isPhoneNumber()
将返回 False
;第一个测试失败,因为“Moshi moshi”长度不足 12 个字符。
如果您想在较大的字符串中查找电话号码,则必须添加更多代码来查找电话号码模式。将 isPhoneNumber.py
中的最后四个 print()
函数调用替换为以下内容:
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
for i in range(len(message)):➊ chunk = message[i:i+12]➋ if isPhoneNumber(chunk):print('Phone number found: ' + chunk)
print('Done')
当这个程序运行时,输出将如下所示:
在 for
循环的每次迭代中,消息中的 12 个字符的新块被分配给变量块 ➊。例如,在第一次迭代中,i 为 0,块被分配为 message[0:12]
(即字符串“Call me at 4”)。在下一次迭代中,i 为 1,块被分配为 message[1:13]
(字符串“all me at 41”)。换句话说,在 for
循环的每次迭代中, chunk
都采用以下值:
您将块传递给 isPhoneNumber()
以查看它是否与电话号码模式 ➋ 匹配,如果是,则打印该块。
继续循环message
,最终chunk中的12个字符将是一个电话号码。该循环遍历整个字符串,测试每个 12 个字符的片段并打印它发现的满足 isPhoneNumber()
的任何块。一旦我们浏览完消息,我们就会打印 Done
。
虽然在此示例中消息中的字符串很短,但它可能有数百万个字符长,并且程序仍将在不到一秒的时间内运行。使用正则表达式查找电话号码的类似程序也将在不到一秒的时间内运行,但正则表达式可以更快地编写这些程序。
Finding Patterns of Text with Regular Expressions
以前的电话号码查找程序可以工作,但它使用大量代码来完成一些有限的事情: isPhoneNumber()
函数有 17 行,但只能查找一种模式的电话号码。电话号码格式如 415.555.4242
或 (415) 555-4242
怎么样?如果电话号码有分机号(例如 415-555-4242 x99
)怎么办? isPhoneNumber()
函数将无法验证它们。您可以为这些附加模式添加更多代码,但有一种更简单的方法。
正则表达式,简称正则表达式,是对文本模式的描述。例如,正则表达式中的 \d 代表数字字符,即从 0 到 9 的任何单个数字。正则表达式 \d\d\d-\d\d\d-\d\d\d\d
Pytho
n 使用 isPhoneNumber(
) 函数来匹配与之前的 isPhoneNumber()
函数相同的文本模式:由三个数字、一个连字符、另外三个数字、另一个连字符和四个数字组成的字符串。任何其他字符串都不会与 \d\d\d-\d\d\d-\d\d\d\d
正则表达式匹配。
但正则表达式可以更加复杂。例如,在模式后添加大括号 ({3}) 中的 3 就像在说“匹配该模式三次”。因此,稍短的正则表达式 \d{3}-\d{3}-\d{4}
也匹配正确的电话号码格式。
Creating Regex Objects
Python 中的所有正则表达式函数都位于 re 模块中。在交互式 shell 中输入以下内容以导入此模块:
Note
本章中的大多数示例都需要 re 模块,因此请记住在您编写的任何脚本的开头或每次重新启动 Mu 时导入它。否则,您将收到 NameError: name 're' is not Defined
错误消息。
将表示正则表达式的字符串值传递给 re.compile()
将返回一个 Regex
模式对象(或简称为 Regex
对象)。
要创建与电话号码模式匹配的 Regex
对象,请在交互式 shell 中输入以下内容。 (请记住, \d
表示“数字字符”,而 \d\d\d-\d\d\d-\d\d\d\d
是电话号码模式的正则表达式。)
>>>phoneNumRegex = re.compile(r’\d\d\d-\d\d\d-\d\d\d\d’)
现在,phoneNumRegex 变量包含一个 Regex 对象。
Matching Regex Objects
Regex
对象的 search()
方法搜索它传递的字符串以查找与正则表达式的任何匹配项。如果在字符串中找不到正则表达式模式,则 search()
方法将返回 None
。如果找到模式,search()
方法将返回一个 Match
对象,该对象有一个 group()
方法,该方法将从搜索字符串中返回实际匹配的文本。 (我将很快解释组。)例如,在交互式 shell
中输入以下内容:
mo
变量名称只是用于 Match
对象的通用名称。这个示例乍一看可能很复杂,但它比之前的 isPhoneNumber.py
程序要短得多,并且执行相同的操作。
在这里,我们将所需的模式传递给 re.compile()
并将生成的 Regex
对象存储在 phoneNumRegex
中。然后我们在 phoneNumRegex
上调用search()
并将我们想要在搜索过程中匹配的字符串传递给 search()
。搜索结果存储在变量 mo
中。在此示例中,我们知道将在字符串中找到我们的模式,因此我们知道将返回一个 Match
对象。知道 mo
包含 Match
对象而不是空值 None
,我们可以在 mo
上调用 group()
以返回匹配项。在 print()
函数调用中写入 mo.group()
会显示整个匹配项,415-555-4242
。
Review of Regular Expression Matching
虽然在 Python 中使用正则表达式有几个步骤,但每个步骤都相当简单。
- 使用 import re 导入正则表达式模块。
- 使用 re.compile() 函数创建 Regex 对象。 (记住使用原始字符串。)
- 将要搜索的字符串传递到 Regex 对象的 search() 方法中。这将返回一个 Match 对象。
- 调用 Match 对象的 group() 方法返回实际匹配文本的字符串。
Note
虽然我鼓励您将示例代码输入交互式 shell,但您还应该使用基于 Web 的正则表达式测试器,它可以准确地向您展示正则表达式如何与您输入的一段文本匹配。我推荐 https://pythex.org/ 上的测试器。
More Pattern Matching with Regular Expressions
既然您已经了解了使用 Python 创建和查找正则表达式对象的基本步骤,您就可以尝试它们的一些更强大的模式匹配功能了。
Grouping with Parentheses
假设您要将区号与电话号码的其余部分分开。添加括号将在正则表达式中创建组:(\d\d\d)-(\d\d\d-\d\d\d\d)
。然后,您可以使用 group()
匹配对象方法从一组中获取匹配文本。
正则表达式字符串中的第一组括号将是组 1。第二组括号将是组 2。通过将整数 1 或 2 传递给 group()
匹配对象方法,您可以抓取匹配文本的不同部分。向 group()
方法传递 0 或不传递任何内容将返回整个匹配的文本。在交互式 shell
中输入以下内容:
如果您想一次检索所有组,请使用 groups() 方法 - 请注意名称的复数形式。
由于 mo.groups()
返回多个值的元组,因此您可以使用多重赋值技巧将每个值分配给单独的变量,如前面的 areaCode, mainNumber = mo.groups()
行中所示。
括号在正则表达式中具有特殊含义,但是如果需要匹配文本中的括号该怎么办?例如,您尝试匹配的电话号码可能在括号中设置了区号。在这种情况下,您需要使用反斜杠转义 ( 和 ) 字符。在交互式 shell
中输入以下内容:
传递给 re.compile()
的原始字符串中的 \(
和 \)
转义字符将与实际的括号字符匹配。在正则表达式中,以下字符具有特殊含义:
. ^ $ * + ? { } [ ] \ | ( )
. ^ $ * + ? { } [ ] \ | ( )
如果您想将这些字符检测为文本模式的一部分,则需要使用反斜杠对它们进行转义:
确保仔细检查您没有将转义括号 ( 和 ) 误认为是正则表达式中的括号 ( 和 )。如果您收到有关“缺少 )”或“不平衡括号”的错误消息,则您可能忘记包含组的未转义右括号,如下例所示:
该错误消息告诉您,r'(\(Parentheses\)'
字符串的索引 0 处有一个左括号,缺少相应的右括号。
Matching Multiple Groups with the Pipe
|
的 |
字符称为管道。您可以在任何想要匹配多个表达式之一的地方使用它。例如,正则表达式 r'Batman|Tina Fey'
将匹配“Batman”
或“Tina Fey”
。
当 Batman
和 Tina Fey
同时出现在搜索字符串中时,第一次出现的匹配文本将作为 Match
对象返回。在交互式 shell
中输入以下内容:
您还可以使用管道来匹配多种模式之一作为正则表达式的一部分。例如,假设您想要匹配任何字符串“Batman”、“Batmobile”、“Batcopter”和“Batbat”。由于所有这些字符串都以 Bat 开头,因此如果您只能指定该前缀一次,那就太好了。这可以通过括号来完成。在交互式 shell 中输入以下内容:
方法调用 mo.group()
返回完整匹配的文本“Batmobile”
,而 mo.group(1)
仅返回第一个括号组“mobile”
内匹配文本的部分。通过使用管道字符和分组括号,您可以指定您希望正则表达式匹配的几种替代模式。
如果需要匹配实际的管道字符,请使用反斜杠对其进行转义,例如 \|
。
Optional Matching with the Question Mark
有时,您只想选择性地匹配某个模式。也就是说,无论该文本是否存在,正则表达式都应该找到匹配项。 ?
字符将其前面的组标记为模式的可选部分。例如,在交互式 shell 中输入以下内容:
(wo)?
正则表达式的一部分表示模式 wo
是可选组。正则表达式将匹配其中包含零个实例或一个 wo
实例的文本。这就是正则表达式同时匹配“Batwoman”
和“Batman”
的原因。
使用前面的电话号码示例,您可以使正则表达式查找包含或不包含区号的电话号码。在交互式 shell 中输入以下内容:
你能想到的吗?
意思是“匹配此问号之前的组中的零个或一个。”
如果需要匹配实际的问号字符,请使用\?
进行转义。
Matching Zero or More with the Star
*(称为星号或星号)表示“匹配零个或多个”——星号之前的组可以在文本中出现任意多次。它可以完全不存在或一遍又一遍地重复。让我们再看一下蝙蝠侠的例子。
对于“Batman”
,正则表达式的(wo)*
部分与字符串中 wo
的零个实例匹配;对于“Batwoman”
,(wo)*
匹配 wo
的一个实例;对于“Batwowowowoman”
,(wo)*
匹配wo
的四个实例。
如果需要匹配实际的星号字符,请在正则表达式中的星号前面加上反斜杠 \*
。
Matching One or More with the Plus
*
表示“匹配零个或多个”,+
(或加号)表示“匹配一个或多个”。与星号不同,星号不要求其组出现在匹配的字符串中,加号前面的组必须至少出现一次。它不是可选的。在交互式shell
中输入以下内容,并将其与上一节中的星号正则表达式进行比较:
正则表达式 Bat(wo)+man
不会匹配字符串“The Adventures of Batman”
,因为加号至少需要一个 wo
。
如果需要匹配实际的加号字符,请在加号前面加上反斜杠以将其转义:\+
。]
Matching Specific Repetitions with Braces
如果您想要重复某个组特定次数,请在正则表达式中的该组后面加上大括号中的数字。例如,正则表达式 (Ha){3}
将匹配字符串“HaHaHa”
,但不会匹配“HaHa”
,因为后者只有两次(Ha)
组重复。
您可以通过在大括号之间写入最小值、逗号和最大值来指定范围,而不是一个数字。例如,正则表达式 (Ha){3,5}
将匹配“HaHaHa”
、“HaHaHaHa”
和“HaHaHaHaHa”
。
您还可以省略大括号中的第一个或第二个数字,以使最小值或最大值不受限制。例如,(Ha){3,}
将匹配 (Ha)
组的三个或多个实例,而 (Ha){,5}
将匹配零到五个实例。大括号可以帮助缩短正则表达式。这两个正则表达式匹配相同的模式:
这两个正则表达式也匹配相同的模式:
在交互式 shell 中输入以下内容:
此处,(Ha){3}
匹配“HaHaHa”
,但不匹配“Ha”
。由于它与“Ha”
不匹配,search()
返回 None
。
Greedy and Non-greedy Matching
由于 (Ha){3,5}
可以匹配字符串 'HaHaHaHaHa'
中的三个、四个或五个Ha
实例,因此您可能想知道为什么上一个大括号示例中Match
对象对 group()
的调用返回'HaHaHaHaHa'
而不是更短的可能性。毕竟,“HaHaHa”
和“HaHaHaHa”
也是正则表达式(Ha){3,5}
的有效匹配。
Python 的正则表达式默认是贪婪的,这意味着在不明确的情况下它们将匹配尽可能长的字符串。大括号的非贪婪(也称为惰性)版本与可能的最短字符串匹配,右大括号后跟一个问号。
在交互式shell
中输入以下内容,并注意搜索同一字符串的大括号的贪婪和非贪婪形式之间的区别:
请注意,问号在正则表达式中可以有两种含义:声明非贪婪匹配或标记可选组。这些含义完全无关。
The findall() Method
除了search()
方法之外,Regex
对象还有 findall()
方法。search()
将返回搜索字符串中第一个匹配文本的 Match
对象,而findall()
方法将返回搜索字符串中每个匹配的字符串。要查看 search()
如何仅在匹配文本的第一个实例上返回 Match
对象,请在交互式 shell
中输入以下内容:
另一方面,只要正则表达式中没有组,findall()
就不会返回 Match
对象,而是返回字符串列表。列表中的每个字符串都是与正则表达式匹配的搜索文本的一部分。在交互式 shell
中输入以下内容:
如果正则表达式中有组,则 findall()
将返回元组列表。每个元组代表一个找到的匹配项,其项是正则表达式中每个组的匹配字符串。要查看 findall()
的实际效果,请在交互式shell
中输入以下内容(请注意,正在编译的正则表达式现在包含括号中的组):
要总结 findall() 方法返回的内容,请记住以下几点:
- 当在没有组的正则表达式上调用时,例如
\d\d\d-\d\d\d-\d\d\d\d
,方法findall()
返回字符串匹配列表,例如[' 415-555-9999','212-555-0000']
。 - 当调用具有组的正则表达式时,例如
(\d\d\d)-(\d\d\d)-(\d\d\d\d)
,方法findall()
返回元组列表字符串(每组一个字符串),例如[('415', '555', '9999'), ('212', '555', '0000')]
。
Character Classes
在前面的电话号码正则表达式示例中,您了解到 \d
可以代表任何数字。也就是说,\d
是正则表达式(0|1|2|3|4|5|6|7|8|9)
的简写。这样的简写字符类有很多,如表 7-1
所示。
Shorthand character class | Represents |
---|---|
\d | 0 到 9 之间的任何数字。 |
\D | 任何非 0 到 9 数字的字符。 |
\w | 任何字母、数字或下划线字符。 (将此视为匹配“单词”字符。) |
\W | 任何非字母、数字或下划线字符的字符。 |
\s | 任何空格、制表符或换行符。 (将此视为匹配“空格”字符。) |
\S | 除空格、制表符或换行符之外的任何字符。 |
字符类非常适合缩短正则表达式。字符类[0-5]
将只匹配数字0到5;这比输入 (0|1|2|3|4|5)
要短得多。请注意,虽然\d
匹配数字,\w
匹配数字、字母和下划线,但不存在仅匹配字母的速记字符类。 (尽管您可以使用[a-zA-Z]
字符类,如下所述。)
例如,在交互式 shell
中输入以下内容:
正则表达式 \d+\s\w+
将匹配包含一个或多个数字 (\d+)
、后跟一个空格字符 (\s)
、后跟一个或多个字母/数字/下划线字符 (\w+)
的文本。 findall()
方法返回列表中正则表达式模式的所有匹配字符串。
Making Your Own Character Classes
有时您想要匹配一组字符,但简写字符类(\d、\w、\s
等)太宽泛。您可以使用方括号定义自己的字符类。例如,字符类[aeiouAEIOU]
将匹配任何元音,包括小写和大写。在交互式 shell
中输入以下内容:
您还可以使用连字符包含字母或数字范围。例如,字符类[a-zA-Z0-9]
将匹配所有小写字母、大写字母和数字。
请注意,方括号内的正常正则表达式符号不会被如此解释。这意味着您不需要使用前面的反斜杠转义.、*、? 或 ()
字符。例如,字符类 [0-5.]
将匹配数字 0 到 5 和句点。不需要写成[0-5\.]
。
通过在字符类的左括号后面放置插入符号 (^)
,可以创建负字符类。负字符类将匹配所有不属于该字符类的字符。例如,在交互式shell
中输入以下内容:
现在,我们不是匹配每个元音,而是匹配每个非元音的字符。
The Caret and Dollar Sign Characters
您还可以在正则表达式的开头使用插入符号 (^) 来指示匹配必须出现在搜索文本的开头。同样,您可以在正则表达式末尾放置一个美元符号 ($)
,以指示字符串必须以此正则表达式模式结尾。您可以一起使用 ^
和 $
来指示整个字符串必须与正则表达式匹配 - 也就是说,仅在字符串的某些子集上进行匹配是不够的。
例如,r'^Hello'
正则表达式字符串匹配以'Hello'
开头的字符串。在交互式shell
中输入以下内容:
r'\d$'
正则表达式字符串匹配以 0 到 9 之间的数字字符结尾的字符串。在交互式 shell
中输入以下内容:
r'^\d+$'
正则表达式字符串匹配以一个或多个数字字符开头和结尾的字符串。在交互式shell
中输入以下内容:
前面的交互式 shell
示例中的最后两个search()
调用演示了如果使用^
和 $
,整个字符串必须如何与正则表达式匹配。
我总是混淆这两个符号的含义,因此我使用助记符“Carrots costdollar”
来提醒自己插入符号在前,美元符号在后。
The Wildcard Character
.
正则表达式中的(或点)字符称为通配符,将匹配除换行符之外的任何字符。例如,在交互式shell
中输入以下内容:
请记住,点字符仅匹配一个字符,这就是为什么上一示例中的文本flat
匹配仅匹配lat
的原因。要匹配实际的点,请使用反斜杠转义点:\..
Matching Everything with Dot-Star
有时您会想要匹配所有内容。例如,假设您想要匹配字符串“First Name:”,后跟任何和所有文本,然后是“Last Name:”,最后再跟任何内容。您可以使用点星号 (.*)
来代表“任何内容”。请记住,点字符表示“除换行符之外的任何单个字符”,星号字符表示“零个或多个前面的字符”。
点星使用贪婪模式:它将始终尝试匹配尽可能多的文本。要以非贪婪方式匹配任何和所有文本,请使用点、星号和问号 (.*?)
。与大括号一样,问号告诉Python
以非贪婪的方式进行匹配。
在交互式shell
中输入以下内容,查看贪婪版本和非贪婪版本之间的区别:
这两个正则表达式大致翻译为“匹配左尖括号,后跟任何内容,然后是右尖括号。”但是字符串 '<Toserve man> fordinner.>'
的右尖括号有两个可能的匹配项。在正则表达式的非贪婪版本中,Python 匹配最短的可能字符串:“<Toserve man>”
。在贪婪版本中,Python 匹配尽可能长的字符串:“<Toserve man> fordinner.>”
。
Matching Newlines with the Dot Character
点星将匹配除换行符之外的所有内容。通过将 re.DOTALL
作为第二个参数传递给 re.compile()
,可以使点字符匹配所有字符,包括换行符。
正则表达式noNewlineRegex
没有将re.DOTALL
传递给创建它的 re.compile()
调用,它只会匹配第一个换行符之前的所有内容,而 newlineRegex
确实将 re.DOTALL
传递给 re.compile( )
,匹配一切。这就是 newlineRegex.search()
调用匹配完整字符串(包括换行符)的原因。
Review of Regex Symbols
Case-Insensitive Matching
通常,正则表达式将文本与您指定的确切大小写进行匹配。例如,以下正则表达式匹配完全不同的字符串:
但有时您只关心匹配字母,而不关心它们是大写还是小写。要使正则表达式不区分大小写,可以将 re.IGNORECASE
或 re.I
作为第二个参数传递给 re.compile()
。在交互式shell
中输入以下内容:
Substituting Strings with the sub() Method
正则表达式不仅可以查找文本模式,还可以用新文本代替这些模式。 Regex 对象的 sub() 方法传递两个参数。第一个参数是一个字符串,用于替换任何匹配项。第二个是正则表达式的字符串。 sub() 方法返回应用了替换的字符串。
例如,在交互式 shell 中输入以下内容:
有时您可能需要使用匹配的文本本身作为替换的一部分。在 sub() 的第一个参数中,您可以键入 \1、\2、\3
等,表示“在替换中输入组 1、2、3
等的文本”。
例如,假设您想通过仅显示秘密特工姓名的第一个字母来审查他们的姓名。为此,您可以使用正则表达式代理 (\w)\w*
并将r'\1****'
作为第一个参数传递给 sub()
。该字符串中的\1
将被第 1 组(即正则表达式的(\w)
组)匹配的任何文本替换。
Managing Complex Regexes
如果您需要匹配的文本模式很简单,则正则表达式就可以了。但匹配复杂的文本模式可能需要长而复杂的正则表达式。您可以通过告诉 re.compile()
函数忽略正则表达式字符串内的空格和注释来缓解这种情况。这种“详细模式”可以通过将变量re.VERBOSE
作为第二个参数传递给re.compile()
来启用。
现在,而不是像这样难以阅读的正则表达式:
您可以使用如下注释将正则表达式分散在多行中:
请注意前面的示例如何使用三引号语法 (‘’') 创建多行字符串,以便您可以将正则表达式定义分散到多行中,从而使其更加清晰。
正则表达式字符串内的注释规则与常规 Python 代码相同:# 符号及其后面到行尾的所有内容都将被忽略。此外,正则表达式的多行字符串内的额外空格不被视为要匹配的文本模式的一部分。这使您可以组织正则表达式,使其更易于阅读。
Combining re.IGNORECASE, re.DOTALL, and re.VERBOSE
What if you want to use re.VERBOSE to write comments in your regular expression but also want to use re.IGNORECASE to ignore capitalization? Unfortunately, the re.compile() function takes only a single value as its second argument. You can get around this limitation by combining the re.IGNORECASE, re.DOTALL, and re.VERBOSE variables using the pipe character (|), which in this context is known as the bitwise or operator.
So if you want a regular expression that’s case-insensitive and includes newlines to match the dot character, you would form your re.compile() call like this:
这种语法有点过时,源自 Python 的早期版本。位运算符的详细信息超出了本书的范围,但请查看 https://nostarch.com/automatestuff2/ 上的资源以获取更多信息。您还可以为第二个参数传递其他选项;它们并不常见,但您也可以在资源中阅读有关它们的更多信息。
Project: Phone Number and Email Address Extractor
假设您有一项无聊的任务:在长网页或文档中查找每个电话号码和电子邮件地址。如果您手动滚动页面,您可能会搜索很长时间。但是,如果您有一个程序可以在剪贴板中的文本中搜索电话号码和电子邮件地址,则只需按 CTRL-A 选择所有文本,按 CTRL-C 将其复制到剪贴板,然后运行您的程序。它可以用它找到的电话号码和电子邮件地址替换剪贴板上的文本。
每当您处理一个新项目时,您都会很想直接开始编写代码。但通常情况下,最好退后一步,考虑更大的前景。我建议首先为您的程序需要做什么制定一个高级计划。现在先不要考虑实际的代码——您可以稍后再考虑。现在,坚持大纲。
例如,您的电话和电子邮件地址提取器需要执行以下操作:
- 将文本从剪贴板中取出。
- 查找文本中的所有电话号码和电子邮件地址。
- 将它们粘贴到剪贴板上。
现在您可以开始思考这在代码中如何工作。该代码需要执行以下操作:
使用pyperclip
模块复制和粘贴字符串。
- 创建两个正则表达式,一个用于匹配电话号码,另一个用于匹配电子邮件地址。
- 查找两个正则表达式的所有匹配项,而不仅仅是第一个匹配项。
- 将匹配的字符串整齐地格式化为单个字符串以进行粘贴。
- 如果在文本中未找到匹配项,则显示某种消息。
该列表就像该项目的路线图。在编写代码时,您可以分别关注其中的每个步骤。每个步骤都相当易于管理,并且用您已经知道如何在 Python 中执行的操作来表达。
Step 1: Create a Regex for Phone Numbers
首先,您必须创建正则表达式来搜索电话号码。创建一个新文件,输入以下内容,并将其另存为 phoneAndEmail.py
:
TODO 注释只是程序的骨架。当您编写实际代码时,它们将被替换。
电话号码以可选的区号开头,因此区号组后跟一个问号。由于区号可以仅为三位数字(即 \d{3})或括号内的三位数字(即 (\d{3})),因此您应该使用管道连接这些部分。您可以将正则表达式注释 # Area code 添加到多行字符串的这一部分,以帮助您记住什么 (\d{3}|(\d{3}))?应该匹配。
电话号码分隔符可以是空格 (\s)、连字符 (-) 或句点 (.),因此这些部分也应该用管道连接。正则表达式的接下来的几个部分很简单:三个数字,后跟另一个分隔符,然后是四个数字。最后一部分是可选的扩展名,由任意数量的空格组成,后跟 ext、x 或 ext.,后跟两到五位数字。
Note
很容易与包含带括号 ( ) 和转义括号 ( ) 的组的正则表达式混淆。如果您收到“缺少 )、未终止的子模式”错误消息,请记住仔细检查您使用的是否正确。
Step 2: Create a Regex for Email Addresses
您还需要一个可以匹配电子邮件地址的正则表达式。使您的程序如下所示:
电子邮件地址 ➊ 的用户名部分是一个或多个字符,可以是以下任意一种:小写和大写字母、数字、点、下划线、百分号、加号或连字符。您可以将所有这些放入一个字符类中:[a-zA-Z0-9._%±]。
域名和用户名由 @ 符号 ➋ 分隔。域名 ➌ 的字符类稍微宽松一些,仅包含字母、数字、句点和连字符:[a-zA-Z0-9.-]。最后是“dot-com”部分(技术上称为顶级域),它实际上可以是任何点。这是两个到四个字符之间。
电子邮件地址的格式有很多奇怪的规则。此正则表达式不会匹配所有可能的有效电子邮件地址,但它会匹配您遇到的几乎所有典型电子邮件地址。
Step 3: Find All Matches in the Clipboard Text
现在您已经指定了电话号码和电子邮件地址的正则表达式,您可以让 Python
的 re
模块完成查找剪贴板上所有匹配项的艰苦工作。 pyperclip.paste()
函数将获取剪贴板上文本的字符串值,findall()
正则表达式方法将返回元组列表。
使您的程序如下所示:
每个匹配项都有一个元组,每个元组包含正则表达式中每个组的字符串。请记住,组 0 匹配整个正则表达式,因此元组索引 0 处的组是您感兴趣的组。
正如您在 ➊ 中看到的,您将把匹配项存储在名为 matches 的列表变量中。它以一个空列表和几个 for 循环开始。对于电子邮件地址,您附加每个匹配项的第 0 组 ➌。对于匹配的电话号码,您不想只附加组 0。虽然程序检测多种格式的电话号码,但您希望附加的电话号码采用单一标准格式。 phoneNum 变量包含一个由匹配文本 ➋ 的第 1、3、5 和 8 组构建的字符串。 (这些组是区号、前三位数字、后四位数字和分机号。)
Step 4: Join the Matches into a String for the Clipboard
现在您已将电子邮件地址和电话号码作为匹配项中的字符串列表,您希望将它们放在剪贴板上。 pyperclip.copy()
函数仅接受单个字符串值,而不是字符串列表,因此您可以在匹配时调用join()
方法。
为了更容易地看到程序正在运行,让我们将找到的任何匹配项打印到终端。如果没有找到电话号码或电子邮件地址,程序应该告诉用户这一点。
使您的程序如下所示:
相关文章:
PYTHON-使用正则表达式进行模式匹配
目录 Python 正则表达式Finding Patterns of Text Without Regular ExpressionsFinding Patterns of Text with Regular ExpressionsCreating Regex ObjectsMatching Regex ObjectsReview of Regular Expression MatchingMore Pattern Matching with Regular ExpressionsGroupi…...
Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)
5、查看证书是否安装成功 方式一: 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项:Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器,选择操作—>查看证书,在搜索…...
架构设计:流式处理与实时计算
引言 随着大数据技术的不断发展,流式处理和实时计算在各行各业中变得越来越重要。那么什么是流式处理呢?我们又该怎么使用它?流式处理允许我们对数据流进行实时分析和处理,而实时计算则使我们能够以低延迟和高吞吐量处理数据。本…...
Linux系统安装zookeeper
Linux安装zookeeper 安装zookeeper之前需要安装jdk,确认jdk环境没问题之后再开始安装zookeeper 下载zookeeper压缩包,官方下载地址:Apache Download Mirrors 将zookeeper压缩包拷贝到Linux并解压 # (-C 路径)可以解压到指定路径 tar -zxv…...
【前端素材】推荐优质后台管理系统Modernize平台模板(附源码)
一、需求分析 后台管理系统是一种用于管理和控制网站、应用程序或系统后台操作的软件工具,通常由授权用户(如管理员、编辑人员等)使用。它提供了一种用户友好的方式来管理网站或应用程序的内容、用户、数据等方面的操作,并且通常…...
二、Vue组件化编程
2、Vue组件化编程 2.1 非单文件组件 <div id"root"><school></school><hr><student></student> </div> <script type"text/javascript">//创建 school 组件const school Vue.extend({template: <div&…...
JVM跨代引用垃圾回收
1. 跨代引用概述 在Java堆内存中,年轻代和老年代之间存在的对象相互引用,假设现在要进行一次新生代的YGC,但新生代中的对象可能被老年代所引用的,为了找到新生代中的存活对象,不得不遍历整个老年代。这样明显效率很低…...
AI:135-基于卷积神经网络的艺术品瑕疵检测与修复
🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…...
C++标准头文件汇总及功能说明
文章目录 algorithmbitsetcctypecerrnoclocalecmathcstdioctimedequeiostreamexceptionfstreamfunctionallimitslistmapiosiosfwdsetsstreamstackstdexceptstreambufcstringutilityvectorcwcharcwctype algorithm algorithm头文件是C的标准算法库,它主要用在容器上。…...
glTF 添加数据属性(extras)
使用3D 模型作为可视化界面的一个关键是要能够在3D模型中添加额外的数据属性,利用这些数据属性能够与后台的信息模型建立对应关系,例如后台信息模型是opcua 信息模型的话,在3D模型中要能够包含OPC UA 的NodeId,BrowserName 等基本…...
linux系统消息中间件rabbitmq普通集群的部署
rabbitmq普通集群的部署 普通集群准备环境查询版本对应安装rabbitmq软件启动创建登录用户开启用户远程登录查看端口 部署集群创建数据存放目录和日志存放目录:拷⻉erlang.cookie将其他两台服务器作为节点加⼊节点集群中查看集群状态创建新的队列 普通集群准备环境 配置hosts⽂件…...
TextCNN:文本分类卷积神经网络
模型原理 1、前言2、模型结构3、示例3.1、词向量层3.2、卷积层3.3、最大池化层3.4、Fully Connected层 4、总结 1、前言 TextCNN 来源于《Convolutional Neural Networks for Sentence Classification》发表于2014年,是一个经典的模型,Yoon Kim将卷积神…...
欧几里得和《几何原本》
欧几里得和《几何原本》 欧几里得(Euclid),公元前约300年生于古希腊,被认为是几何学的奠基人之一。他的主要成就是编写了一本名为《几何原本》(Elements)的著作,这本书成为了几何学的经典教材&a…...
linux c++ 开发 tensorrt 安装
tensorrt 官方下载地址(需要注册账号登录):Log in | NVIDIA Developer 根据系统发行版和CUDA版本 (nvcc -V) 选择合适的安装包 EA(early access)版本代表抢先体验。 GA(general availability)代…...
Redis高并发分布锁实战
Redis高并发分布锁实战 问题场景 场景一: 没有捕获异常 // 仅仅加锁 // 读取 stock15 Boolean ret stringRedisTemplate.opsForValue().setIfAbsent("lock_key", "1"); // jedis.setnx(k,v) // TODO 业务代码 stock-- stringRedisTemplate.delete(&quo…...
Kotlin基础——DSL
DSL(领域特定语言) 常见的DSL就是SQL和正则表达式,用于操作数据库和文本字符串,Kotlin DSL通常为嵌套的Lambda表达式或链式方法,如 https://github.com/gradle/gradle-script-kotlin 用于构建Gradle脚本https://gith…...
《Docker 简易速速上手小册》第4章 Docker 容器管理(2024 最新版)
文章目录 4.1 容器生命周期管理4.1.1 重点基础知识4.1.2 重点案例:启动并管理 Python Flask 应用容器4.1.3 拓展案例 1:调试运行中的容器4.1.4 拓展案例 2:优雅地停止和清理容器 4.2 容器数据管理与持久化4.2.1 重点基础知识4.2.2 重点案例&a…...
【人脸朝向识别与分类预测】基于PNN神经网络
课题名称:基于PNN神经网络的人脸朝向识别分类 版本日期:2024-02-20 运行方式:直接运行PNN0503.m文件 代码获取方式:私信博主或 QQ:491052175 模型描述: 采集到一组人脸朝向不同角度时的图像,图像来自不…...
【Python笔记-设计模式】组合模式
一、说明 组合模式是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们。 (一) 解决问题 处理树形结构:可以很好地处理树形结构的数据,使得用户可以统一对待单个对象和对象组合。统一接…...
51单片机学习(5)-----蜂鸣器的介绍与使用
前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步。 目录 一. 蜂鸣器的介绍 1.蜂鸣器介绍 2.压电式蜂鸣器 (无源…...
-bash: /root/.ssh/authorized_keys: Read-only file system
问题背景 由于跳板机不支持 ssh-copy-id 命令,为了配置免密登录,考虑在服务器上手动使用 cat 命令写入跳板机公钥 cat <<EOL >> ~/.ssh/authorized_keys [Your public key] EOL但却出现了以下错误 -bash: /root/.ssh/authorized_keys: Re…...
3,设备无关位图显示
建立了一个类Dib Dib.h #pragma once #include “afx.h” class CDib :public CObject { public: CDib(); ~CDib(); char* GetFileName(); BOOL IsValid(); DWORD GetSize(); UINT GetWidth(); UINT GetHeight(); UINT GetNumberOfColors(); RGBQUAD* GetRGB(); BYTE* GetDat…...
转前端了!!
大家好,我是冰河~~ 没错,为了更好的设计和开发分布式IM即时通讯系统,也为了让大家能够直观的体验到分布式IM即时通讯系统的功能,冰河开始转战前端了。也就是说,整个项目从需求立项到产品设计,从架构设计到…...
RESTful API如何使用它构建 web 应用程序。
链接:华为机考原题 RESTful API(Representational State Transfer)是一种基于网络的软件架构风格,用于设计和访问网络资源。它是一种轻量级、灵活、可扩展的架构,常用于构建Web应用程序和服务。 使用RESTful API构建Web应用程序的步骤如下&…...
现在学Oracle是49年入国军么?
今天周末,不聊技术,聊聊大家说的最多的一个话题 先说明一下,防止挨喷😆 本人并不是职业dba,对数据库就是爱好,偶尔兼职,以下仅个人观点分析,如有不同观点请轻喷,哈哈&…...
【回溯】组合问题||
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示例 1: 输入: candidates [10,1,2,7,6,…...
【c语言】字符函数和字符串函数(下)
前言 书接上回 【c语言】字符函数和字符串函数(上) 上一篇讲解的strcpy、strcat、strcmp函数的字符串长度是不受限制的 而本篇strncpy、strncat、strcnmp函数的字符串长度是受限制的 欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,…...
基于Java的艺培管理解决方案
✍✍计算机毕业编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java、…...
Python算法题集_实现 Trie [前缀树]
Python算法题集_实现 Trie [前缀树] 题208:实现 Trie (前缀树)1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【定义数据类默认字典】2) 改进版一【初始化字典无额外类】3) 改进版二【字典保存结尾信息无额外类】 4. 最优算法5. 相关…...
pytorch简单新型模型测试参数
import torch from torch.nn import Conv2d,MaxPool2d,Sequential,Flatten,Linear import torchvision import torch.optim.optimizer from torch.utils.data import DataLoader,dataset from torch import nn import torch.optim.optimizer# 建模 model nn.Linear(2,1)#损失 …...
珠海专业做网站公司/大数据营销的概念
Web后门工具WeBaCooWeBaCoo是使用Perl语言编写的Web后门工具。渗透测试人员首先使用该工具生成一个后门PHP页面。然后,将该页面上传到目标服务器上。最后,在本地终端直接访问该页面,WeBaCoo将执行的命令Base64编码后,借助Cookie的…...
房产机构网站建设/互联网营销专家
BeautifulSoup BeautifulSoup 是一个非常流行的 python 模块,该模块可以解析网页,并提供定位内容的便捷接口。安装简便 pip install beautifulsoup4 第一步是将已下载的 HTML 内容解析为 soup 文档。由于大多数网页都不具备良好的 html 格式ÿ…...
瓯北网站制作报价/seo智能优化公司
为什么80%的码农都做不了架构师?>>> 在java和一些常用的数据中(mysql/sqlsever)中进行年月日分秒转换的时候,都是用 SELECT to_char(CURRENT_DATE,yyyy-MM-dd hh:MM:ss) 但是在Postgresql中这样用就会出现问题,在pg中执行上面的语…...
直播是网站怎么做/今天的重要新闻
getchar()的用法,部分内容参考百度百科 getchar()函数功能是从stdio中读字符 注:getchar有一个int型的返回值,当程序调用getcahr时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回…...
网站建设技术和销售工资/指数基金有哪些
新的项目开始了,这一次是做一个网站类似于QQ空间那样的,基本功能比如说写日志,说说之类的都要有(说说是要有楼中楼嵌套的,应该能够上传图片),还要可以修改个人信息。登录注册之类的更不用说了&a…...
vps装网站管理系统/个人免费推广网站
nginx根据域名后缀流入不同的项目 简介:我们的项目是前后端分离,前端使用vue写的 话不多说,贴配置文件文件 user www www; worker_processes auto; error_log /www/wwwlogs/nginx_error.log crit; pid /www/server/nginx/logs/n…...