核心要点
最常用的匹配任意字符的元字符是 (点号),但它有一个非常重要的限制:默认情况下,它不匹配换行符 \n。

下面我们详细讲解几种方法。
(点号) - 最常用但不匹配换行符
是正则表达式中最基础的通配符,它会匹配除了换行符 \n 之外的任何单个字符。
示例 1:基本用法
import re
text = "Python is fun, and regex is powerful!"
pattern = r"fun.*powerful" # 匹配 "fun" 和 "powerful" 之间的任意字符(不含换行)
match = re.search(pattern, text)
if match:
print(f"找到匹配: {match.group()}")
# 输出: 找到匹配: fun, and regex is powerful
else:
print("未找到匹配")
在这个例子中, 表示匹配零个或多个任意字符(除了换行符),成功找到了匹配项。
示例 2:不匹配换行符的局限性
import re
text = """This is the first line.
And this is the second line."""
pattern = r"first.*second" # 试图匹配跨越两行的内容
match = re.search(pattern, text)
if match:
print(f"找到匹配: {match.group()}")
else:
print("未找到匹配") # 输出: 未找到匹配
为什么失败? 因为 不能匹配 first 和 second 之间的换行符 \n,所以整个模式匹配失败。

re.DOTALL (或 re.S) 标志 - 让 匹配所有字符(包括换行符)
如果你需要 也匹配换行符,可以在正则表达式函数(如 re.search, re.findall)中传入 re.DOTALL 标志(它的别名是 re.S,因为 S 代表 "Single line",这是一种有点误导但很常见的叫法)。
示例:使用 re.DOTALL 解决跨行匹配
import re
text = """This is the first line.
And this is the second line."""
pattern = r"first.*second"
# 使用 re.DOTALL 标志
match = re.search(pattern, text, re.DOTALL) # 或者 re.search(pattern, text, re.S)
if match:
print(f"找到匹配: {match.group()}")
# 输出: 找到匹配: first line.
# And this is the second line.
else:
print("未找到匹配")
这次匹配成功了,因为 re.DOTALL 告诉 元字符,它现在可以匹配包括 \n 在内的任何字符。
[\s\S] - 跨平台且不依赖标志的技巧
这是一个非常强大和常用的技巧,它不依赖于任何标志,可以在任何正则表达式引擎中工作。
\s匹配任何空白字符(包括\n,\t,\r,\f,\v和空格)。\S匹配任何非空白字符。
把它们放在一个字符组 [] 里,[\s\S] 的意思就是“匹配一个要么是空白字符,要么是非空白字符的字符”。这等价于“匹配任何字符”。

示例:使用 [\s\S] 跨行匹配
import re
text = """This is the first line.
And this is the second line."""
pattern = r"first[\s\S]*second" # 使用 [\s\S] 代替 .
match = re.search(pattern, text)
if match:
print(f"找到匹配: {match.group()}")
# 输出: 找到匹配: first line.
# And this is the second line.
else:
print("未找到匹配")
这个方法同样有效,并且代码看起来更“纯粹”,因为它没有依赖外部标志,在一些复杂的正则表达式中,这种方法更清晰。
\W 和 \w - 匹配字母、数字和下划线(及其反面)
虽然它们不匹配“所有”字符,但也是描述“任意”字符的一种方式,非常常用。
\w(word character) 匹配任何字母、数字或下划线 ([a-zA-Z0-9_])。\W(non-word character) 匹配任何非字母、数字或下划线的字符(, , , ,`,\n` 等)。
示例
import re text = "User_ID: 123, Name: John_Doe, Score: 99.5!" # 匹配一个单词字符序列 pattern_word = r"\w+" print(re.findall(pattern_word, text)) # 输出: ['User', 'ID', '123', 'Name', 'John', 'Doe', 'Score', '99', '5'] # 匹配一个非单词字符序列 pattern_nonword = r"\W+" print(re.findall(pattern_nonword, text)) # 输出: [': ', ', ', ': ', ' ', '.', '!']
总结与对比
| 方法/元字符 | 描述 | 是否匹配换行符 | 如何使用 | 适用场景 |
|---|---|---|---|---|
| 匹配除换行符外的任何单个字符 | 否 | re.search(r"a.b", text) |
简单的单行文本匹配。 | |
re.DOTALL |
标志,使 匹配所有字符(包括换行符) | 是 | re.search(r"a.b", text, re.DOTALL) |
需要跨多行进行模糊匹配的场景。 |
[\s\S] |
匹配任何单个字符(空白或非空白) | 是 | re.search(r"a[\s\S]b", text) |
跨行匹配,且不希望或不能使用 re.DOTALL 标志。 |
\w |
匹配字母、数字、下划线 | 否 (它本身不是通配符) | re.findall(r"\w+", text) |
匹配单词、变量名、ID等。 |
\W |
匹配非字母、数字、下划线的字符 | 是 (因为它包含 \n) |
re.findall(r"\W+", text) |
匹配分隔符、标点符号等。 |
最佳实践建议
- 明确需求:首先问自己,“我是否需要匹配跨越多行的文本?”
- 首选
re.DOTALL:如果可以修改函数调用(即能传入标志),re.DOTALL是最直观、最易读的解决方案。 - 备用
[\s\S]:如果由于某些原因(正则表达式是动态构建的,或者来自外部)不能使用标志,[\s\S]是一个非常可靠和强大的替代方案。 - 谨慎使用 :始终记住 的默认行为是不匹配换行符,除非你明确知道这一点并利用它,否则很容易在处理多行文本时出错。
