0

0

Python正则表达式怎么用?文本匹配技巧

雪夜

雪夜

发布时间:2025-08-12 12:12:02

|

419人浏览过

|

来源于php中文网

原创

python正则表达式通过re模块实现文本匹配与处理,1.常用函数包括re.search()查找首个匹配、re.match()从开头匹配、re.findall()获取所有匹配、re.sub()替换匹配内容、re.compile()预编译模式提升效率;2.核心语法涵盖通配符、量词、字符集、分组、转义等,支持复杂模式构建;3.高级技巧包括贪婪与非贪婪控制、分组捕获与非捕获、匹配标志应用如忽略大小写和多行模式;4.性能优化需预编译正则、避免灾难性回溯;5.常见陷阱涉及原始字符串缺失、match与search混淆、字符集内元字符误解;6.适用场景为模式匹配、结构化数据提取、动态替换等复杂文本处理,而简单操作优先使用字符串方法。

Python正则表达式怎么用?文本匹配技巧

Python的正则表达式,说白了,就是一套用来描述和匹配字符串模式的强大工具。它通过一套特殊的字符序列(也就是“正则模式”)来查找、替换或提取文本中符合特定规则的内容。在Python里,我们主要通过内置的

re
模块来使用它,这玩意儿在处理各种文本数据时简直是利器。

Python正则表达式怎么用?文本匹配技巧

解决方案

要用好Python的正则表达式,核心在于理解

re
模块提供的几个关键函数和基本的正则语法。

首先,你需要导入

re
模块:
import re

立即学习Python免费学习笔记(深入)”;

Python正则表达式怎么用?文本匹配技巧

最常用的几个函数:

  • re.search(pattern, string, flags=0)
    : 这个函数会在整个字符串中查找第一个匹配
    pattern
    的位置。如果找到,返回一个匹配对象(Match object),否则返回
    None
    。它只会返回第一个匹配结果,如果你想找所有的,就得循环或者用
    findall

    Python正则表达式怎么用?文本匹配技巧
    text = "我的电话是138-0000-1234,工作电话是010-87654321。"
    # 查找手机号
    match = re.search(r'\d{3}-\d{4}-\d{4}', text)
    if match:
        print(f"找到手机号: {match.group()}") # 输出:找到手机号: 138-0000-1234
  • re.match(pattern, string, flags=0)
    : 和
    search
    类似,但
    match
    只从字符串的开头进行匹配。如果模式不在字符串的起始位置,它就找不到。

    text1 = "Hello World"
    text2 = "World Hello"
    print(re.match(r'Hello', text1)) # 
    print(re.match(r'Hello', text2)) # None
  • re.findall(pattern, string, flags=0)
    : 这个函数会找到字符串中所有不重叠的
    pattern
    匹配,并以列表的形式返回所有匹配的字符串。

    text = "电子邮件地址有:test@example.com 和 info@domain.org。"
    emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', text)
    print(f"找到的邮箱: {emails}")
    # 输出:找到的邮箱: ['test@example.com', 'info@domain.org']
  • re.sub(pattern, repl, string, count=0, flags=0)
    : 替换字符串中所有匹配
    pattern
    的部分为
    repl
    count
    参数可以限制替换的次数。

    text = "我喜欢苹果,也喜欢香蕉,还喜欢苹果。"
    new_text = re.sub(r'苹果', '橘子', text)
    print(f"替换后: {new_text}") # 输出:替换后: 我喜欢橘子,也喜欢香蕉,还喜欢橘子。
  • re.compile(pattern, flags=0)
    : 当你需要多次使用同一个正则表达式模式时,用
    re.compile()
    预编译它会更高效。它返回一个正则表达式对象,然后你可以在这个对象上调用
    search
    findall
    等方法。

    phone_pattern = re.compile(r'\d{3}-\d{4}-\d{4}')
    text1 = "我的电话是138-0000-1234。"
    text2 = "联系方式是139-1111-2222。"
    print(phone_pattern.search(text1).group())
    print(phone_pattern.search(text2).group())

一些常用的正则语法元素:

  • .
    : 匹配除换行符以外的任意字符。
  • *``**: 匹配前一个字符零次或多次。
  • +
    : 匹配前一个字符一次或多次。
  • ?
    : 匹配前一个字符零次或一次(也用于非贪婪匹配)。
  • []
    : 字符集,匹配方括号内的任意一个字符。例如
    [abc]
    匹配 'a', 'b', 或 'c'。
    [0-9]
    匹配任意数字。
  • ()
    : 分组,可以用来捕获匹配的内容,或者对多个字符应用量词。
  • |
    : 或,匹配左右两边的任意一个模式。例如
    cat|dog
    匹配 'cat' 或 'dog'。
  • ^
    : 匹配字符串的开始。
  • $
    : 匹配字符串的结束。
  • \
    : 转义字符,用于匹配特殊字符本身,例如
    \.
    匹配点号。
  • \d
    : 匹配任意数字(等同于
    [0-9]
    )。
  • \w
    : 匹配字母、数字或下划线(等同于
    [A-Za-z0-9_]
    )。
  • \s
    : 匹配任意空白字符(空格、制表符、换行符等)。
  • \b
    : 匹配单词边界。

记住,在Python中使用正则表达式时,最好使用原始字符串(raw string),即在字符串前加

r
,例如
r'\d+'
。这样可以避免反斜杠被Python解释器误认为是转义字符,导致不必要的麻烦。

Python正则表达式在处理文本数据时有哪些高级应用技巧?

说实话,高级技巧这东西,很多时候就是把基础元素玩出花来。我个人觉得,真正能提升你正则功力的,除了熟练运用基本语法,就是理解一些更微妙的概念和功能了。

一个很有用的概念是贪婪与非贪婪匹配。默认情况下,量词(如

*
,
+
,
?
,
{m,n}
)都是“贪婪”的,它们会尽可能多地匹配字符。但有时候我们希望它尽可能少地匹配,这时就可以在量词后面加上一个问号
?
,使其变为“非贪婪”模式。

比如,你想从

这是一个段落

这是另一个段落

中只提取第一个

...

。 如果用
r'

.*

'
,它会匹配到
这是一个段落

这是另一个段落

,因为
.*
会一直匹配到最后一个

。 但如果用
r'

.*?

VidAU
VidAU

VidAU AI 是一款AI驱动的数字人视频创作平台,旨在简化视频内容创作流程

下载
'
.*?
就会非贪婪地匹配到第一个

处,这样就能正确地提取出
这是一个段落

。这个小小的
?
真是解决了不少头疼的问题。

另一个我觉得挺实用的是分组与捕获。用括号

()
创建的分组,不仅可以对一部分模式应用量词,还能捕获匹配到的内容。你可以通过匹配对象的
group(index)
方法来获取这些捕获到的子字符串。 比如,从日期字符串 "2023-10-26" 中分别提取年、月、日:

date_str = "2023-10-26"
match = re.search(r'(\d{4})-(\d{2})-(\d{2})', date_str)
if match:
    year = match.group(1) # 2023
    month = match.group(2) # 10
    day = match.group(3) # 26
    print(f"年: {year}, 月: {month}, 日: {day}")

有时候你只想分组,但不想捕获内容,可以使用非捕获分组

(?:...)
。这在构建复杂模式时很有用,可以避免创建不必要的捕获组,提升一点点性能,主要是让你的匹配对象更干净。

还有就是正则表达式的标志(Flags)

re
模块提供了一些标志,可以改变匹配的行为。比如:

  • re.IGNORECASE
    re.I
    : 忽略大小写。
  • re.MULTILINE
    re.M
    : 让
    ^
    $
    不仅匹配字符串的开始/结束,还匹配每一行的开始/结束(在多行模式下)。
  • re.DOTALL
    re.S
    : 让
    .
    匹配包括换行符在内的所有字符。这在处理跨越多行的文本块时特别有用。
text_multiline = "第一行\n第二行"
# 默认情况下,. 不匹配换行符
print(re.search(r'.+', text_multiline).group()) # 第一行
# 使用 re.DOTALL,. 匹配换行符
print(re.search(r'.+', text_multiline, re.DOTALL).group()) # 第一行\n第二行

这些高级应用,其实就是对基本概念的灵活组合和对细节的把握。我发现很多人一开始会觉得这些概念有点绕,但一旦理解了,文本处理能力会提升一大截,能解决很多以前觉得无从下手的问题。

Python正则表达式性能优化与常见陷阱有哪些?

谈到性能和陷阱,这真是个老生常谈但又不得不提的话题。我记得有一次,一个简单的正则就让程序卡死了好几秒,后来才发现是贪婪匹配惹的祸。

性能优化方面:

一个很重要的点是预编译正则表达式。如果你需要在一个程序中多次使用同一个正则表达式模式,强烈建议使用

re.compile()

# 不推荐,每次调用都会重新编译
for _ in range(10000):
    re.search(r'\d+', 'abc123def')

# 推荐,只编译一次
compiled_pattern = re.compile(r'\d+')
for _ in range(10000):
    compiled_pattern.search('abc123def')

虽然对于简单的模式和少量操作,差异不明显,但在处理大量文本或复杂模式时,性能提升是显而易见的。

另一个需要注意的,是避免“灾难性回溯”(Catastrophic Backtracking)。这通常发生在模式中包含嵌套的量词,并且这些量词可以匹配空字符串或者重叠匹配时。比如

(a+)+
或者
(a|aa)+
这样的模式。当输入字符串不匹配时,正则表达式引擎会尝试所有可能的匹配路径,导致指数级的回溯,从而使程序变得非常慢,甚至看起来像死机了一样。 解决办法通常是:

  • 使用非贪婪匹配 (
    *?
    ,
    +?
    )。
  • 优化模式,使其更精确,减少不必要的重复匹配。
  • 避免过度嵌套的重复组
  • 如果可能,考虑使用更简单的字符串方法或者分步匹配

常见陷阱:

  1. 忘记使用原始字符串(Raw Strings):前面提过,

    r''
    可以避免反斜杠的转义问题。如果你写
    '\n'
    ,Python会把它解释成换行符,而不是匹配字母 'n' 的字面量。写成
    r'\n'
    才是匹配反斜杠和字母 'n'。这个小细节经常让人犯错。

  2. re.match()
    re.search()
    的混淆
    :我见过不少人,明明想在整个字符串中查找,却误用了
    re.match()
    ,结果发现总是返回
    None
    。记住,
    match
    只看开头,
    search
    才是全局扫描。

  3. 贪婪与非贪婪的误解:这绝对是初学者最常踩的坑。我上面已经详细解释了,这里就不再赘述了。但记住,当你发现匹配结果比你预期的长时,多半就是贪婪匹配在作祟。

  4. 字符集

    []
    内的特殊字符:在
    []
    内部,很多元字符(如
    .
    ,
    *
    ,
    +
    ,
    ?
    ,
    |
    ,
    (
    ,
    )
    ,
    {
    ,
    ^
    ,
    $
    )会失去它们的特殊含义,被当作普通字符处理。但
    \
    ]
    仍然需要转义(除非
    ]
    是第一个字符)。例如,要匹配
    [foo]
    ,你得写
    r'\[foo\]'
    。而
    [.
    匹配的是字面量点号。

  5. 编码问题:当处理非ASCII字符(比如中文)时,确保你的字符串和正则表达式模式的编码是一致的。Python 3 默认处理Unicode字符串,通常问题不大,但如果你从文件读取数据,或者涉及到不同编码的系统交互,就得注意了。

总的来说,写正则就像写代码,需要测试和调试。当结果不符预期时,不要急着改代码,先仔细检查你的正则表达式,甚至可以利用在线的正则测试工具来逐步调试。

Python中什么时候该用正则表达式,什么时候用普通的字符串方法?

这是一个非常实用的问题,我个人在实际工作中也经常面临这样的选择。我的经验是,如果一个任务能用简单的字符串方法解决,就尽量不用正则。 正则虽然强大,但它的可读性确实比普通字符串方法差一些,而且写起来也更容易出错。

什么时候应该用普通的字符串方法?

  • 简单的查找和替换:如果你只是想查找一个固定的子字符串是否存在,或者用一个固定的字符串替换另一个固定的字符串,那么
    in
    运算符、
    str.find()
    ,
    str.index()
    ,
    str.replace()
    这些方法就足够了,而且它们通常更快。
    text = "Hello World"
    if "World" in text: # 简单的查找
        print("Found World")
    new_text = text.replace("World", "Python") # 简单的替换
  • 判断字符串开头或结尾
    str.startswith()
    str.endswith()
    比用
    ^
    $
    的正则表达式更直观、更高效。
    filename = "report.txt"
    if filename.endswith(".txt"):
        print("这是一个文本文件")
  • 简单的分割字符串:如果你的分隔符是固定的,
    str.split()
    是首选。
    data = "apple,banana,orange"
    fruits = data.split(',')
  • 大小写转换、去除空白等
    str.lower()
    ,
    str.upper()
    ,
    str.strip()
    等方法功能单一且高效。

什么时候应该用正则表达式?

  • 模式匹配:当你需要查找的不是一个固定的字符串,而是一种“模式”时,正则表达式是不可替代的。比如查找所有符合邮箱格式的字符串、所有电话号码、所有日期格式等。
    # 查找所有形如 "YYYY-MM-DD" 的日期
    text = "项目启动日期是2023-10-26,截止日期是2024-01-15。"
    dates = re.findall(r'\d{4}-\d{2}-\d{2}', text)
  • 复杂的字符串验证:验证用户输入是否符合特定格式(如密码强度、URL格式、身份证号等),正则表达式能提供简洁而强大的表达能力。
  • 基于模式的替换:当你需要替换的内容不是固定的,而是根据匹配到的模式来动态生成时,
    re.sub()
    结合分组捕获非常强大。
    # 将 "姓 名" 格式改为 "名 姓"
    name = "张 三"
    new_name = re.sub(r'(\S+)\s+(\S+)', r'\2 \1', name) # \1 \2 引用捕获组
    print(new_name) # 三 张
  • 从非结构化文本中提取结构化数据:比如从日志文件、网页HTML、配置文件中提取特定信息。这通常是正则表达式大显身手的地方。

很多时候,两者还会结合使用。比如,你可能先用

str.splitlines()
把一个大文本分割成行,然后对每一行使用正则表达式来提取或验证信息。

我的建议是,从最简单的方法开始考虑。如果

str
方法能解决,就用它。如果不行,或者需要处理的模式比较复杂、多变,那才是正则表达式出场的时候。熟练掌握两者的边界,能让你在文本处理时事半功倍。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

772

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

661

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

764

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

679

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1365

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

570

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

730

2023.08.11

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

4

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 14.1万人学习

Django 教程
Django 教程

共28课时 | 3.4万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号