Python 正则表达式完整教程:从入门到精通
序言:字符串处理的利器
在数据处理、文本分析、网络爬虫等众多领域,我们经常需要对字符串进行复杂的查找、匹配、替换和分割操作。面对海量、格式各异的文本数据,传统的字符串方法(如 str.find()
, str.replace()
, str.split()
)往往显得力不从心。此时,正则表达式 (Regular Expression) 便闪亮登场,成为处理字符串的强大工具。
正则表达式是一种用于描述字符串模式的强大语言,它可以简洁而精准地表达复杂的匹配规则。Python 内建了对正则表达式的支持,通过 re
模块,我们可以轻松地在 Python 中使用正则表达式进行各种字符串处理任务。
本教程将带你深入了解 Python 中正则表达式的使用,从基础概念、常用语法到 re
模块的各种函数,直至一些进阶技巧和实战应用,助你掌握这一强大的工具。
第一部分:正则表达式基础语法
在开始使用 Python 的 re
模块之前,我们首先需要理解正则表达式自身的语法。正则表达式由普通字符和元字符组成。普通字符匹配其本身,而元字符则具有特殊的含义。
1. 普通字符 (Literal Characters)
大多数字符(如字母、数字)都属于普通字符,它们会匹配文本中完全相同的字符。
示例:cat
会匹配字符串中的 “cat”。
2. 元字符 (Metacharacters)
元字符是正则表达式的精髓,它们不匹配字符本身,而是表达一种匹配规则或位置。常用的元字符包括:
.
:匹配任意单个字符(除了换行符\n
)。- 示例:
a.c
可以匹配 “abc”, “aac”, “a9c” 等。
- 示例:
^
:匹配字符串的开头。- 示例:
^Hello
只匹配以 “Hello” 开头的字符串。
- 示例:
$
:匹配字符串的结尾。- 示例:
world$
只匹配以 “world” 结尾的字符串。
- 示例:
*
:匹配前面的元素零次或多次。- 示例:
a*
可以匹配 “”, “a”, “aa”, “aaa” 等。
- 示例:
+
:匹配前面的元素一次或多次。- 示例:
a+
可以匹配 “a”, “aa”, “aaa” 等,但不匹配 “”。
- 示例:
?
:匹配前面的元素零次或一次。- 示例:
colou?r
可以匹配 “color” 或 “colour”。
- 示例:
{n}
:匹配前面的元素恰好 n 次。- 示例:
a{3}
只匹配 “aaa”。
- 示例:
{n,}
:匹配前面的元素至少 n 次。- 示例:
a{2,}
可以匹配 “aa”, “aaa”, “aaaa” 等。
- 示例:
{n,m}
:匹配前面的元素至少 n 次,至多 m 次。- 示例:
a{2,4}
可以匹配 “aa”, “aaa”, “aaaa”。
- 示例:
|
:或运算符,匹配 | 符号前或后的表达式。- 示例:
cat|dog
可以匹配 “cat” 或 “dog”。
- 示例:
()
:分组,将多个字符作为一个整体处理,也用于捕获匹配的文本(捕获组)。- 示例:
(ab)+
匹配 “ab”, “abab”, “ababab” 等。
- 示例:
\
:转义字符,用于匹配元字符本身。- 示例:要匹配字符
.
,你需要使用\.
。要匹配\
本身,你需要使用\\
。
- 示例:要匹配字符
3. 字符集 (Character Sets)
使用方括号 []
可以定义一个字符集,匹配方括号内的任意一个字符。
[abc]
:匹配 ‘a’, ‘b’, 或 ‘c’ 中的任意一个字符。[a-z]
:匹配任意小写字母。[A-Z]
:匹配任意大写字母。[0-9]
:匹配任意数字。[a-zA-Z0-9]
:匹配任意字母或数字。[^abc]
:匹配除了 ‘a’, ‘b’, ‘c’ 之外的任意字符。^
在字符集内部表示取反。
4. 预定义字符集 (Special Sequences)
为了方便,正则表达式还提供了一些预定义的特殊字符序列,它们是常用字符集的简写:
\d
:匹配任意数字,等价于[0-9]
。\D
:匹配任意非数字字符,等价于[^0-9]
。\w
:匹配任意字母、数字或下划线,等价于[a-zA-Z0-9_]
。常用于匹配“单词字符”。\W
:匹配任意非字母、数字、下划线字符,等价于[^a-zA-Z0-9_]
。\s
:匹配任意空白字符(空格、制表符、换行符等),等价于[\t\n\r\f\v]
。\S
:匹配任意非空白字符,等价于[^\t\n\r\f\v]
。\b
:匹配单词边界,即一个单词字符和非单词字符之间的位置,或者单词字符与字符串开头/结尾之间的位置。- 示例:
\bcat\b
只匹配独立的单词 “cat”,不会匹配 “catalog” 中的 “cat”。
- 示例:
\B
:匹配非单词边界。- 示例:
\Bcat\B
可以匹配 “catalog” 中的 “cat”,但不会匹配独立的单词 “cat”。
- 示例:
5. 贪婪与非贪婪匹配 (Greedy vs. Non-greedy)
默认情况下,正则表达式的量词(*
, +
, ?
, {n,m}
等)是贪婪的 (greedy),它们会尽可能多地匹配字符。
示例:用 <.*>
去匹配字符串 <b>Hello</b><i>World</i>
贪婪模式会匹配 <b>Hello</b><i>World</i>
整个字符串。
非贪婪模式则是在量词后面加上 ?
,使其尽可能少地匹配字符。
示例:用 <.*?>
去匹配字符串 <b>Hello</b><i>World</i>
非贪婪模式会匹配 <b>
和 <i>
。
常用的非贪婪量词:*?
, +?
, ??
, {n,m}?
。
6. Raw String (原始字符串)
在 Python 中,反斜杠 \
是一个转义字符。这会与正则表达式中的反斜杠产生冲突。例如,正则表达式 \n
表示换行,但在 Python 字符串中 "\n"
也表示换行。为了避免混淆和大量的双重反斜杠(如 \\d
才能表示 \d
),强烈建议使用 Python 的原始字符串 (Raw String) 来书写正则表达式。
原始字符串在引号前加上 r
或 R
,其中的反斜杠不会被解释为转义字符。
示例:r"\d+"
比 "\\d+"
更清晰地表示匹配一个或多个数字。
第二部分:Python 的 re
模块
Python 标准库中的 re
模块提供了所有正则表达式相关的功能。使用它之前需要先导入:
python
import re
re
模块提供了多个函数用于执行不同的正则表达式操作。
1. re.search(pattern, string, flags=0)
在整个 string
中查找第一个匹配 pattern
的位置。如果找到,返回一个匹配对象 (Match Object);如果没有找到,返回 None
。
“`python
import re
text = “The quick brown fox jumps over the lazy dog.”
查找单词 ‘fox’
match = re.search(r”fox”, text)
if match:
print(“Found match:”, match.group()) # match.group() 返回匹配到的字符串
else:
print(“No match found.”)
查找数字 (此处文本中没有数字)
match_num = re.search(r”\d+”, text)
if match_num:
print(“Found number:”, match_num.group())
else:
print(“No number found.”)
“`
2. re.match(pattern, string, flags=0)
尝试从 string
的开头匹配 pattern
。如果从开头就匹配成功,返回一个匹配对象;否则,即使后续部分有匹配,也返回 None
。
这是 re.search()
与 re.match()
的主要区别:match()
只检查字符串的开头,而 search()
会扫描整个字符串。
“`python
import re
text = “Hello world, hello Python.”
从开头匹配 ‘Hello’
match1 = re.match(r”Hello”, text)
if match1:
print(“match1 found:”, match1.group()) # 输出: match1 found: Hello
从开头匹配 ‘world’
match2 = re.match(r”world”, text)
if match2:
print(“match2 found:”, match2.group())
else:
print(“match2 not found (doesn’t start with ‘world’).”) # 输出: match2 not found…
使用 search 查找 ‘world’
search_match = re.search(r”world”, text)
if search_match:
print(“search_match found:”, search_match.group()) # 输出: search_match found: world
“`
3. re.findall(pattern, string, flags=0)
在 string
中查找所有非重叠的 pattern
匹配项,并以列表的形式返回所有匹配到的字符串。
“`python
import re
text = “Emails: [email protected], [email protected], [email protected]”
查找所有单词 (\w+ 表示一个或多个单词字符)
words = re.findall(r”\w+”, text)
print(“Words:”, words) # 输出: Words: [‘Emails’, ‘test’, ‘example’, ‘com’, ‘info’, ‘domain’, ‘org’, ‘user’, ‘mail’, ‘co’, ‘uk’]
查找简单的邮箱格式
(这里只是一个非常简化的邮箱匹配,实际应用中需要更复杂的模式)
emails = re.findall(r”\w+@\w+.\w+”, text)
print(“Simple Emails:”, emails) # 输出: Simple Emails: [‘[email protected]’, ‘[email protected]’]
“`
如果模式中有捕获组 ()
,findall
会返回一个列表,列表的每个元素是捕获组匹配到的内容的元组(如果只有一个捕获组,则直接是字符串列表)。
“`python
text = “Name: Alice Age: 30; Name: Bob Age: 25”
查找姓名和年龄
matches = re.findall(r”Name: (\w+) Age: (\d+)”, text)
print(“Name and Age matches:”, matches) # 输出: Name and Age matches: [(‘Alice’, ’30’), (‘Bob’, ’25’)]
“`
4. re.finditer(pattern, string, flags=0)
在 string
中查找所有非重叠的 pattern
匹配项,并以迭代器的形式返回所有匹配到的匹配对象。当处理大量匹配项时,使用迭代器可以更节省内存。
“`python
import re
text = “Numbers: 123, 456, 789”
查找所有数字
for match in re.finditer(r”\d+”, text):
print(“Found number:”, match.group(), “at position:”, match.span())
输出:
Found number: 123 at position: (9, 12)
Found number: 456 at position: (14, 17)
Found number: 789 at position: (19, 22)
“`
5. re.sub(pattern, repl, string, count=0, flags=0)
在 string
中找到所有匹配 pattern
的子串,并用 repl
替换它们。
pattern
: 要匹配的正则表达式。repl
: 替换的字符串。它可以是字符串,也可以是一个函数。- 如果
repl
是字符串,它可以使用\g<name>
或\g<number>
来引用捕获组的内容。 - 如果
repl
是函数,它会接收每个匹配对象作为参数,并返回替换后的字符串。
- 如果
string
: 要进行替换操作的原始字符串。count
: 最大替换次数。默认为 0,表示替换所有匹配项。flags
: 可选的匹配标志。
“`python
import re
text = “Hello world! 123 ABC.”
将所有非单词字符替换为空格
cleaned_text = re.sub(r”\W+”, ” “, text)
print(“Cleaned text:”, cleaned_text) # 输出: Cleaned text: Hello world 123 ABC
将数字替换为 [NUMBER]
anonymized_text = re.sub(r”\d+”, “[NUMBER]”, text)
print(“Anonymized text:”, anonymized_text) # 输出: Anonymized text: Hello world! [NUMBER] ABC.
使用捕获组引用进行替换(交换姓和名)
name = “Smith, John”
模式解释: (\w+) 捕获一个或多个单词字符作为组1 (姓)
, 匹配逗号和空格
(\w+) 捕获一个或多个单词字符作为组2 (名)
替换解释: \g<2> 引用组2, \g<1> 引用组1
formatted_name = re.sub(r”(\w+), (\w+)”, r”\g<2> \g<1>”, name)
print(“Formatted name:”, formatted_name) # 输出: Formatted name: John Smith
使用函数进行替换 (将数字加倍)
def double_number(match):
num = int(match.group(0)) # 获取匹配到的数字字符串并转为整数
return str(num * 2) # 返回加倍后的数字字符串
text_with_numbers = “Items: 10, Price: 50, Quantity: 3″
doubled_text = re.sub(r”\d+”, double_number, text_with_numbers)
print(“Doubled numbers:”, doubled_text) # 输出: Doubled numbers: Items: 20, Price: 100, Quantity: 6
“`
6. re.split(pattern, string, maxsplit=0, flags=0)
根据 pattern
中匹配到的子串来分割 string
。返回一个列表,包含分割后的所有子串。
pattern
: 用于分割的正则表达式。string
: 要被分割的字符串。maxsplit
: 最大分割次数。默认为 0,表示不限制分割次数。flags
: 可选的匹配标志。
“`python
import re
text = “apple,banana;orange grapes”
使用逗号或分号或空格进行分割
parts = re.split(r”[,;\s]”, text)
print(“Split parts:”, parts) # 输出: Split parts: [‘apple’, ‘banana’, ‘orange’, ‘grapes’]
限制分割次数
parts_limited = re.split(r”[,;\s]”, text, maxsplit=1)
print(“Split parts (max 1):”, parts_limited) # 输出: Split parts (max 1): [‘apple’, ‘banana;orange grapes’]
“`
如果分割模式中包含捕获组 ()
,那么捕获到的分隔符本身也会包含在结果列表中。
python
text = "hello-world+python"
parts_with_delimiters = re.split(r"(-|\+)", text)
print("Split with delimiters:", parts_with_delimiters) # 输出: Split with delimiters: ['hello', '-', 'world', '+', 'python']
7. re.compile(pattern, flags=0)
将正则表达式 pattern
编译成一个正则表达式对象。编译后的对象有 search()
, match()
, findall()
, finditer()
, sub()
, split()
等方法,与 re
模块顶层的同名函数功能相同。
当需要多次使用同一个正则表达式模式时,编译它可以提高效率,因为编译过程只需要执行一次。
“`python
import re
编译正则表达式对象
regex = re.compile(r”\d+”)
text1 = “Number 123”
text2 = “Value is 456”
text3 = “ID 789”
使用编译后的对象进行匹配
match1 = regex.search(text1)
match2 = regex.search(text2)
all_numbers = regex.findall(text3)
if match1:
print(“Match 1:”, match1.group())
if match2:
print(“Match 2:”, match2.group())
print(“All numbers in text3:”, all_numbers)
“`
第三部分:匹配对象 (Match Object)
re.search()
和 re.match()
函数在找到匹配时会返回一个匹配对象。这个对象包含了匹配到的详细信息,可以通过其方法获取这些信息:
match.group(0)
或match.group()
:返回整个匹配到的字符串。match.group(n)
:返回第 n 个捕获组(()
包围的部分)匹配到的字符串。组编号从 1 开始。match.groups()
:返回一个元组,包含所有捕获组匹配到的字符串。match.start()
:返回匹配到的子串在原字符串中的起始索引。match.end()
:返回匹配到的子串在原字符串中的结束索引(不包含该索引处的字符)。match.span()
:返回一个元组(start, end)
,包含匹配到的子串的起始和结束索引。
“`python
import re
text = “Python version is 3.9”
查找版本号(主版本号.次版本号)
(\d+) 是第一个捕获组,匹配数字
. 匹配字符 ‘.’
(\d+) 是第二个捕获组,匹配数字
match = re.search(r”version is (\d+).(\d+)”, text)
if match:
print(“Full match:”, match.group(0)) # 或 match.group()
print(“Major version:”, match.group(1)) # 组 1
print(“Minor version:”, match.group(2)) # 组 2
print(“All groups:”, match.groups()) # (‘3’, ‘9’)
print(“Start index:”, match.start()) # 15 (version is 后面的 v 的索引)
print(“End index:”, match.end()) # 21 (9 后面一个字符的索引)
print(“Span:”, match.span()) # (15, 21)
# 根据 span 提取原字符串中的匹配部分
print("Extracted from string:", text[match.start():match.end()]) # version is 3.9
“`
第四部分:匹配标志 (Flags)
re
模块的许多函数(search
, match
, findall
, finditer
, sub
, split
, compile
)都接受一个可选的 flags
参数,用于修改匹配的行为。常用的标志包括:
re.IGNORECASE
或re.I
:忽略大小写进行匹配。- 示例:
re.search(r"apple", "Apple Pie", re.I)
会匹配成功。
- 示例:
re.MULTILINE
或re.M
:使^
和$
不仅匹配整个字符串的开头和结尾,还匹配每一行的开头和结尾(在换行符\n
之后和之前)。- 没有
re.M
:^pattern$
只匹配整个字符串就是 pattern 的情况。 - 有
re.M
:
text = "Line 1\nLine 2\nLine 3"
# 匹配每一行的开头 'Line'
re.findall(r"^Line", text, re.M) # ['Line', 'Line', 'Line']
# 匹配每一行的结尾数字
re.findall(r"\d+$", text, re.M) # ['1', '2', '3']
- 没有
re.DOTALL
或re.S
:使元字符.
匹配包括换行符\n
在内的任意字符。默认情况下.
不匹配换行符。- 示例:
re.search(r"a.b", "a\nb")
默认不会匹配,但加上re.S
后会匹配成功。
- 示例:
re.VERBOSE
或re.X
:允许在正则表达式中添加空白字符(空格、制表符、换行符)和注释(以#
开头),以提高可读性。忽略空白字符,除非它们被转义或包含在字符集[]
中。- 示例:
python
pattern = r"""
^(\d{3}) # 匹配开头的三位数字 (区号)
-? # 匹配可选的连字符
(\d{3}) # 匹配接下来的三位数字
-? # 匹配可选的连字符
(\d{4})$ # 匹配结尾的四位数字
"""
match = re.search(pattern, "123-456-7890", re.X)
# pattern 即使包含大量空白和注释,也能正确匹配
- 示例:
可以通过位运算符 |
组合多个标志,例如 re.I | re.M
。
“`python
import re
text = “First LINE\nsecond line”
查找所有以 ‘line’ 开头且忽略大小写的行
matches = re.findall(r”^line”, text, re.I | re.M)
print(matches) # 输出: [‘First LINE’, ‘second line’]
“`
第五部分:进阶话题
1. 非捕获组 (Non-capturing Groups)
有时候我们需要使用 ()
进行分组,但并不需要捕获分组匹配到的文本。这时可以使用非捕获组 (?:...)
。非捕获组不占用捕获组编号,也不会在 match.groups()
或 re.findall()
中返回。
“`python
import re
text = “cat|dog|fox”
使用捕获组 split
parts_capture = re.split(r”(?:|)”, text) # 注意:在 split 中使用捕获组 (|) 会保留分隔符
print(“Split with non-capturing group:”, parts_capture) # 输出: [‘cat’, ‘dog’, ‘fox’]
对比使用捕获组 split
parts_capture_alt = re.split(r”(|)”, text)
print(“Split with capturing group:”, parts_capture_alt) # 输出: [‘cat’, ‘|’, ‘dog’, ‘|’, ‘fox’]
在 findall 中对比
text_numbers = “abc123def456ghi”
使用捕获组查找数字
nums_capture = re.findall(r”([a-z]+)(\d+)”, text_numbers)
print(“Findall with capturing groups:”, nums_capture) # 输出: [(‘abc’, ‘123’), (‘def’, ‘456’)]
使用非捕获组查找数字 (只关心数字本身)
nums_non_capture = re.findall(r”(?:[a-z]+)(\d+)”, text_numbers)
print(“Findall with non-capturing group:”, nums_non_capture) # 输出: [‘123’, ‘456’] (只返回捕获组的内容)
“`
2. 零宽断言 (Lookarounds)
零宽断言是一种特殊的结构,它们匹配一个位置,而不是实际的字符。它们用于在匹配某个模式时,检查其前面或后面的文本是否符合特定的模式,但不将这些文本包含在最终的匹配结果中。
(?=...)
:正向肯定预查 (Positive Lookahead)。匹配后面是...
的位置。- 示例:
Python(?=程序员)
匹配 “Python” 这个词,但仅当它后面紧跟着 “程序员” 时。在 “Python程序员很棒” 中,它会匹配 “Python”,但匹配结果只有 “Python”,不包含 “程序员”。
- 示例:
(?!=...)
:正向否定预查 (Negative Lookahead)。匹配后面不是...
的位置。- 示例:
Python(?! 2)
匹配 “Python” 这个词,但仅当它后面不紧跟着 ” 2″ (空格和数字2) 时。在 “Python 3” 中匹配 “Python”,在 “Python 2” 中不匹配。
- 示例:
(?<=...)
:反向肯定预查 (Positive Lookbehind)。匹配前面是...
的位置。- 示例:
(?<=¥)\d+
匹配数字,但仅当它前面紧跟着 “¥” 时。在 “总价¥100元” 中,它会匹配 “100”,但匹配结果只有 “100”,不包含 “¥”。
- 示例:
(?<!...)
:反向否定预查 (Negative Lookbehind)。匹配前面不是...
的位置。- 示例:
(?<!\$)\d+
匹配数字,但仅当它前面不紧跟着 “$” 时。在 “总价¥100元” 中匹配 “100”,在 “Cost$50” 中不匹配 “50”。
- 示例:
“`python
import re
text = “apple juice, banana smoothie, orange juice”
查找后面跟着 ‘ juice’ 的单词
words_before_juice = re.findall(r”\w+(?= juice)”, text)
print(“Words before juice:”, words_before_juice) # 输出: Words before juice: [‘apple’, ‘orange’]
查找前面跟着 ‘banana ‘ 的单词
word_after_banana = re.findall(r”(?<=banana )\w+”, text)
print(“Word after banana:”, word_after_banana) # 输出: Word after banana: [‘smoothie’]
查找不是以 ‘le’ 结尾的单词
words_not_end_le = re.findall(r”\b\w+(?!le)\b”, text)
print(“Words not ending with ‘le’:”, words_not_end_le) # 输出: Words not ending with ‘le’: [‘banana’, ‘smoothie’, ‘orange’, ‘juice’]
注意:上面的匹配可能包含不符合预期的结果,因为 \b 的位置问题。一个更精确的可能是 \b(?!\w*le\b)\w+\b
另一个例子:查找不以数字结尾的单词
text_mixed = “word1 word2 ok3 not4 good”
words_not_end_digit = re.findall(r”\b\w+(?!\d)\b”, text_mixed)
print(“Words not ending with digit:”, words_not_end_digit) # 输出: Words not ending with digit: [‘word1’, ‘word2’, ‘good’]
“`
零宽断言非常强大,但有时也难以理解和书写。它们适用于需要根据上下文进行匹配,但又不希望上下文成为匹配结果一部分的场景。
第六部分:实用技巧与最佳实践
- 始终使用原始字符串 (Raw String): 正则表达式中大量使用反斜杠
\
,使用r"..."
可以避免 Python 自身的转义干扰。 - 编译重复使用的模式: 如果同一个正则表达式需要多次用于不同的字符串或同一个字符串的多个操作,使用
re.compile()
编译它,可以显著提高性能。 - 从小处着手,逐步构建: 复杂的正则表达式很难一次写对。从匹配最基本的部分开始,然后逐步添加更多的规则和限制。
- 使用在线工具测试: 有许多在线的正则表达式测试工具(如 regex101.com, regextester.com)可以帮助你实时调试和可视化你的正则表达式。
- 添加注释 (使用
re.VERBOSE
): 对于复杂的模式,使用re.VERBOSE
标志并添加注释可以极大地提高可读性和可维护性。 - 优先使用非正则表达式方法: 对于简单的字符串操作(如判断开头/结尾、简单的替换、查找固定子串),Python 的内置字符串方法(
startswith()
,endswith()
,replace()
,find()
,in
运算符等)通常更简单、更高效、更易读。只在需要模式匹配时使用正则表达式。 - 注意贪婪与非贪婪: 当使用量词匹配变长内容时,思考你需要的是尽可能多的匹配(默认贪婪)还是尽可能少的匹配(非贪婪,加
?
)。 - 捕获组的编号问题: 默认从 1 开始,非捕获组
(?:...)
不占用编号。
第七部分:常见应用场景举例
1. 验证格式 (简单示例)
验证一个字符串是否是有效的邮政编码(假设为 6 位数字):
“`python
import re
def is_valid_postal_code(code):
# ^ 匹配开头, \d{6} 匹配恰好6个数字, $ 匹配结尾
pattern = r”^\d{6}$”
return re.match(pattern, code) is not None
print(is_valid_postal_code(“100000”)) # True
print(is_valid_postal_code(“12345”)) # False
print(is_valid_postal_code(“123456a”)) # False
“`
2. 提取特定信息
从一段文本中提取所有的 URL (简化版本,实际 URL 模式非常复杂):
“`python
import re
text = “Visit our website at https://www.example.com or check http://sub.domain.org/path”
查找以 http:// 或 https:// 开头,后面跟着非空白字符的序列
urls = re.findall(r”https?://\S+”, text)
print(“Found URLs:”, urls) # 输出: Found URLs: [‘https://www.example.com’, ‘http://sub.domain.org/path’]
“`
3. 文本清理
去除文本中的 HTML 标签 (简单版本,实际清理需要更健壮的库):
“`python
import re
html_text = “
This is a bold and italic text.
“
查找 < 后跟任意非 > 字符零次或多次,再跟 >
cleaned_text = re.sub(r”<[^>]+>”, “”, html_text)
print(“Cleaned text:”, cleaned_text) # 输出: Cleaned text: This is a bold and italic text.
“`
4. 数据转换/重排
将 “YYYY-MM-DD” 格式的日期转换为 “MM/DD/YYYY” 格式:
“`python
import re
date_str = “The date is 2023-10-27.”
模式: (\d{4}) 捕获年份, (\d{2}) 捕获月份, (\d{2}) 捕获日期
替换: 使用 \g<2> (月)/\g<3> (日)/\g<1> (年) 的顺序
formatted_date = re.sub(r”(\d{4})-(\d{2})-(\d{2})”, r”\g<2>/\g<3>/\g<1>”, date_str)
print(“Formatted date:”, formatted_date) # 输出: Formatted date: The date is 10/27/2023.
“`
结论
正则表达式是处理文本数据的强大武器,Python 的 re
模块提供了丰富的功能来使用它。掌握正则表达式语法和 re
模块的常用函数,能让你更高效、更灵活地处理各种字符串相关的任务。
本教程覆盖了正则表达式的基础语法、Python re
模块的核心函数、匹配对象的用法、常用标志以及一些进阶技巧和实用示例。正则表达式的世界非常广阔,还有更多高级特性(如原子组、递归匹配等),但本教程的内容足以应对绝大多数日常开发需求。
学习正则表达式最好的方法就是实践。尝试用正则表达式解决你遇到的字符串处理问题,多加练习,逐步熟悉各种模式和函数的使用。祝你在正则表达式的学习和使用中取得成功!