首页 > 编程语言 >Python正则表达式实践

Python正则表达式实践

时间:2024-05-29 20:10:57浏览次数:13  
标签:字符 匹配 re Python pattern 实践 正则表达式 match

Python正则表达式实践

1. 正则表达式简介

正则表达式是一种用来描述或匹配字符串的模式。它广泛应用于字符串搜索、替换和解析。

2. 导入re模块

Python中的正则表达式功能主要由re模块提供。你可以通过以下方式导入它:

import re

3. 正则表达式基本语法

3.1 匹配单个字符

  • . 匹配除换行符外的任意字符。
  • \w 匹配字母、数字或下划线或汉字。
  • \W 匹配非字母、数字、下划线。
  • \d 匹配数字。
  • \D 匹配非数字。
  • \s 匹配空白字符(包括空格、制表符、换行符等)。
  • \S 匹配非空白字符。

3.2 字符类

  • [abc] 匹配字符a、b或c。
  • [^abc] 匹配除a、b、c之外的任意字符。
  • [a-z] 匹配任意小写字母。
  • [A-Z] 匹配任意大写字母。
  • [aeiou]匹配元音字母。
  • [0-9] 匹配任意数字,等价于\d。
  • [a-z0-9A-Z] 等价于\w(如果只考虑英文的话)。
  • [.?!]匹配标点符号(.或?或!)

3.3 量词

  • * 匹配前一个字符0次或多次。
  • + 匹配前一个字符1次或多次。
  • ? 匹配前一个字符0次或1次。
  • {n} 匹配前一个字符n次。
  • {n,} 匹配前一个字符至少n次。
  • {n,m} 匹配前一个字符n到m次。

3.4 边界匹配

  • ^ 匹配字符串的开头。

  • $ 匹配字符串的结尾。

  • \b 匹配单词边界(开始或结束)。

  • \B 匹配非单词边界。

3.5 分支条件

正则表达式中的分支条件语法使用竖线 | 来表示多个选择中的一个。例如,pattern1|pattern2 表示匹配 pattern1pattern2。具体用法如下:

  • a|b 匹配 ab
  • (cat|dog) 匹配 catdog

当多个条件中有一个匹配成功时,整个表达式就匹配成功。这在处理复杂模式匹配时非常有用。例如,正则表达式 Jan|Feb|Mar 匹配 "Jan"、"Feb" 或 "Mar"。

在使用正则表达式的分支条件时,有以下注意事项:

  1. 匹配顺序:从左到右匹配,一旦找到匹配项,就不会继续尝试其他分支。
  2. 优先级:用小括号 () 可以明确分支的优先级。例如,(a|b)c 匹配 acbc,而 a|bc 匹配 abc
  3. 效率问题:分支条件过多时,匹配效率可能会下降,建议优化正则表达式以提高性能。
  4. 贪婪匹配:默认情况下,正则表达式是贪婪的,尽可能多地匹配字符。

3.6 分组

分组在正则表达式中用于捕获子模式,并用圆括号 () 来表示。

  1. 捕获组(pattern),将 pattern 作为一个组,例如,(abc) 匹配并捕获 "abc"。

  2. 非捕获组(?:pattern),匹配 pattern 但不捕获,例如,(?:abc) 只匹配 "abc" 而不保存。

  3. 命名组(?P<name>pattern),匹配并捕获到名为 name 的组,例如,(?P<word>\w+) 匹配并捕获一个单词。

    注意:在 Python 的正则表达式库 re 中,命名捕获组的语法与其他一些语言(如 JavaScript 或 .NET)有所不同。Python 使用的是 (?P<name>pattern) 语法,而不是 (?<name>pattern)

  4. 引用分组\number\g<name>,引用之前捕获的组,例如,(\d+)-\1 匹配重复的数字。

示例:

  • (a|b)c 匹配 "ac" 或 "bc"。

  • (?P<digit>\d) 捕获一个数字并命名为 "digit"。

使用正则表达式进行IPv4地址匹配:

  1. \b(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}\b
  2. \b(?:\d{1,3}\.){3}\d{1,3}\b

上面的pattern1仅仅会匹配到正确的IPv4地址,下面的pattern2虽然可以匹配到正确的IPv4地址,但是像256.300.888.999这种不正确的地址也会匹配。

3.7 后向引用

正则表达式中的后向引用(backreference)允许你在正则表达式中引用之前捕获的子表达式。

后向引用的语法是使用 \ 后跟数字 n,其中 n 是一个从 1 开始的正整数,表示捕获组的索引。捕获组是用圆括号 () 包围的正则表达式。

例如我们要匹配一个重复的单词,如 apple apple,可以使用后向引用来实现:

  • 正则表达式:(\w+)\s+\1
  • 解释:
    • (\w+) 匹配并捕获第一个单词 apple
    • \s+ 匹配一个或多个空白字符。
    • \1 是后向引用,引用第一个捕获组 (\w+) 中匹配到的内容,这里就是 apple

这个正则表达式将匹配 apple apple 中的重复单词。

后向引用在需要确保重复的内容一致性时非常有用,例如在查找 HTML 标签的开头和结尾是否匹配时,或者查找重复的词语等情况下。

3.8 零宽断言

零宽断言(zero-width assertions)是正则表达式中非常强大的特性,它允许你指定一个位置,而不是字符,来匹配一个模式。零宽断言不消耗字符,也就是说,它们是零宽度的,只是检查位置是否符合条件。

以下是零宽断言的四种类型及其对比示例:

类型 语法 描述 示例正则表达式 示例匹配文本 匹配结果
正向零宽断言 (?=pattern) 断言后面的内容要匹配 pattern \d+(?= years) 25 years old 25
负向零宽断言 (?!pattern) 断言后面的内容不匹配 pattern \d+(?! years) 25 months old 25
正向零宽断言(逆向) (?<=pattern) 断言前面的内容要匹配 pattern (?<=\$)\d+ $25 25
负向零宽断言(逆向) (?<!pattern) 断言前面的内容不匹配 pattern (?<!\$)\d+ 25 dollars 25

3.9 注释

使用 (?#comment) 语法在正则表达式内部添加注释。

注释类型 语法 作用 示例
内联注释 (?#comment) 在正则表达式内部添加注释 \d{3}(?# Area Code)-\d{4}

除了上述的语法,也可以使用处理选项re.VERBOSE添加注释。

小括号()相关语法汇总

分组,引用,捕获,零宽断言,注释都用到了小括号的语法,每个特性在正则表达式中都有其特定的用途和语法。

特性 语法 作用 示例 说明
分组 (pattern) 将多个字符或子模式组合在一起 (abc)+ 匹配一个或多个 abc
捕获 (pattern) 捕获并存储匹配的内容 (\d{3})-(\d{4}) 捕获三个数字和四个数字
引用 \n\k<name> 引用前面捕获的内容 (\w+)\s+\1 匹配重复的单词
非捕获组 (?:pattern) 分组但不捕获内容 (?:abc)+ 匹配一个或多个 abc 不捕获
命名组 (?<name>pattern) 为捕获的分组指定一个名称 (?\d{4})-(?\d{2})-(?\d{2}) 捕获日期字符串中的年份,月份和日志,并使用命名组引用
正向零宽断言 (?=pattern) 断言当前位置后面的内容要匹配 pattern \d+(?= years) 后面紧跟 years 的数字
负向零宽断言 (?!pattern) 断言当前位置后面的内容不匹配 pattern \d+(?! years) 后面不能跟 years 的数字
正向零宽断言(逆向) (?<=pattern) 断言当前位置前面的内容要匹配 pattern (?<=\$)\d+ 前面紧跟 $ 的数字
负向零宽断言(逆向) (?<!pattern) 断言当前位置前面的内容不匹配 pattern (?<!\$)\d+ 前面不能跟 $ 的数字
注释 (?#comment) 添加注释以提高可读性 \d{3}(?# Area Code)-\d{4} 区号注释

3.10 贪婪与懒惰

在正则表达式中,贪婪(greedy)和懒惰(lazy,也称为非贪婪或者勉强的)是描述匹配模式如何工作的两种不同方式。

  1. 贪婪匹配

    • 贪婪模式尽可能匹配更多的字符。
    • 贪婪量词默认是贪婪的,例如 *, +, ?, {n,} 等。
    • 例如,正则表达式 a.*b 会匹配尽可能长的以 a 开始、以 b 结尾的字符串。
  2. 懒惰匹配(也称为非贪婪或勉强的):

    • 懒惰模式会尽可能少的匹配字符。
    • 在贪婪量词后面加上 ? 可以将其转换为懒惰模式。
    • 例如,a.*?b 会匹配尽可能短的以 a 开始、以 b 结尾的字符串。

下面是一些常见的贪婪量词和它们的懒惰版本:

  • *:贪婪 *,懒惰 *?
  • +:贪婪 +,懒惰 +?
  • ?:贪婪 ?,懒惰 ??
  • {n,}:贪婪 {n,},懒惰 {n,}?
  • {n,m}:贪婪 {n,m},懒惰 {n,m}?

贪婪模式是默认的,如果你想要一个懒惰的模式,你需要在量词后面加上 ? 符号。

区别比 贪婪模式 懒惰模式
定义 尽可能多地匹配字符。 尽可能少地匹配字符。
量词 默认是贪婪的,例如 *, +, {n,} 等。 在贪婪量词后面加上 ? 来表示懒惰,如 *?, +?, {n,}?
示例1 a.*c 匹配 abbbcabc 中的整个字符串。 a.*?c 匹配 abbc 中的 abbc
示例2 <div>.*</div> 匹配 <div>first</div><div>second</div> 整个字符串。 <div>.*?</div> 分别匹配 <div>first</div><div>second</div>

3.11 处理选项

正则表达式处理选项(也称为标志或修饰符)用于改变正则表达式的行为。

处理选项 简写 描述 示例
re.IGNORECASE re.I 忽略大小写匹配 re.search(r"hello", "Hello", re.I)
re.MULTILINE re.M 多行模式,^$ 匹配每行 re.search(r"^hello", "hello\nworld", re.M)
re.DOTALL re.S 使 . 匹配包括换行符在内的所有字符 re.search(r"hello.*world", "hello\nworld", re.S)
re.VERBOSE re.X 允许使用空白符和注释以提高可读性 re.search(r"(?x) \d{3} # 区号\n-\d{4} # 本地号码", "123-4567")
re.ASCII re.A 使 \w, \b, \s 等仅匹配 ASCII 字符 re.search(r"\w+", "café", re.A)
re.LOCALE re.L 依赖当前的区域设置进行匹配 re.search(r"\w+", "café", re.L)
re.UNICODE re.U 使 \w, \b, \s 等匹配所有 Unicode 字符 re.search(r"\w+", "café", re.U)
re.DEBUG 输出编译后的正则表达式字节码 re.compile(r"\d+", re.DEBUG)

4. 常用函数

4.1 re.match()

在字符串的开头尝试匹配一个模式。如果匹配成功,返回一个匹配对象,否则返回None。

import re

pattern = r'hello'
text = 'hello world'
match = re.match(pattern, text)
if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

4.2 re.search()

扫描整个字符串并返回第一个成功的匹配。

import re

pattern = r'world'
text = 'hello world'
match = re.search(pattern, text)
if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

4.3 re.findall()

返回所有与模式匹配的子串列表。

import re

pattern = r'\d+'
text = 'There are 2 apples and 5 oranges'
matches = re.findall(pattern, text)
print("匹配结果:", matches)

4.4 re.sub()

替换字符串中所有匹配正则表达式的子串。

import re

pattern = r'apples'
replacement = 'bananas'
text = 'I like apples'
new_text = re.sub(pattern, replacement, text)
print("替换结果:", new_text)

4.5 re.split()

用于根据匹配的正则表达式模式拆分字符串。

import re

# 定义一个字符串
text = 'apple,banana;cherry orange:grape'

# 使用正则表达式匹配逗号、分号、冒号和空格
pattern = r'[;,\s:]+'

# 使用 re.split() 拆分字符串
result = re.split(pattern, text)

print(result)  # 输出 ['apple', 'banana', 'cherry', 'orange', 'grape']

4.5 re.compile()

将正则表达式模式编译为正则表达式对象,提高匹配效率。

import re

pattern = re.compile(r'\d+')
result = pattern.findall('123abc456')
print(result)  # 输出 ['123', '456']

当我们在Python中使用正则表达式时,re模块内部会干两件事情:

  1. 编译正则表达式,如果正则表达式的字符串本身不合法,会报错;

  2. 用编译后的正则表达式去匹配字符串。

如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配。

7. 代码示例

1. 捕获组/非捕获组

捕获组允许你提取子字符串。

import re

pattern = r'(\d{3})-(\d{2})-(\d{4})'
text = '123-45-6789'
match = re.match(pattern, text)
if match:
    print("完整匹配:", match.group(0))
    print("第一组:", match.group(1))
    print("第二组:", match.group(2))
    print("第三组:", match.group(3))

(?:...) 定义非捕获组,匹配内容但不捕获。

import re

pattern = r'(?:\d{3})-(\d{2})-(\d{4})'
text = '123-45-6789'
match = re.match(pattern, text)
if match:
    print("完整匹配:", match.group(0))
    print("第二组:", match.group(1))
    print("第三组:", match.group(2))  # 注意: 这里的组数是从1开始的,因为非捕获组不算在内

2. 注释相关的示例代码

匹配一个包含可选国家代码的国际电话号码

import re

phone_pattern = re.compile(r'''
    (\+\d{1,3})?   # 可选的国际区号,如 +1, +44
    \s?            # 可选的空格
    \(\d{1,4}\)    # 区号在括号内
    \s?            # 可选的空格
    \d{1,4}        # 前缀(如前面的三位数)
    [-\s]?         # 可选的短横线或空格
    \d{1,4}        # 后缀(如后面的四位数)
    ([-\s]\d{1,4})* # 可选的其他数字段(适用于多个国家)
    ''', re.VERBOSE)

match = phone_pattern.search('+1 (123) 456-7890')
print(match.group())  # 输出: +1 (123) 456-7890

3. 提取邮件地址中的名字

以下示例展示了如何提取名字,假设名字可能在尖括号内或为电子邮件的本地部分。

import re

def extract_name(text):
    # 尝试匹配尖括号中的名字
    match = re.search(r'<([^>]+)>', text)
    if match:
        return match.group(1)
    
    # 尝试匹配电子邮件地址的本地部分
    match = re.search(r'([^@]+)@', text)
    if match:
        return match.group(1)
    
    # 如果都没有匹配到,返回None
    return None

# 测试例子
examples = [
    "<Tom Paris> [email protected]",
    "[email protected]"
]

for example in examples:
    print(f"Input: {example}")
    print(f"Extracted Name: {extract_name(example)}\n")

解释正则表达式 r'<([^>]+)>'

  1. r'...':

    前缀 r 表示原始字符串 (raw string),在 Python 中,原始字符串中的反斜杠不会被转义。这对于正则表达式非常有用,因为正则表达式中通常会包含很多反斜杠字符。

  2. <:

    匹配一个字符 <,表示字符串中的左尖括号。

  3. ([^>]+):

    • 这是一个捕获组,表示我们感兴趣的部分将被捕获,以供后续引用。
    • [] 之间的内容表示一个字符类,匹配一组字符中的任意一个。
    • ^ 放在字符类的开头,表示取非,即匹配除右尖括号 > 之外的任意字符。
    • + 表示前面的字符类匹配一次或多次,即至少要匹配一个字符。
  4. >:

    匹配一个字符 >,表示字符串中的右尖括号。

总结一下,正则表达式 r'<([^>]+)>' 的含义是:

  • 匹配一个左尖括号 <
  • 匹配并捕获左尖括号和右尖括号之间的所有字符(只要这些字符不是 >)。
  • 匹配一个右尖括号 >

因此,捕获组 ([^>]+) 将提取出字符串 Tom Paris

说明:

在正则表达式中, ^ 有不同的含义,这取决于它的上下文:

  • 在字符类中(例如 [^...]),^ 表示取非,匹配不在字符类中的字符。
  • 在字符类外(例如 ^...),^ 表示行开头,匹配行的开头位置。

8. 参考资料

标签:字符,匹配,re,Python,pattern,实践,正则表达式,match
From: https://www.cnblogs.com/lldhsds/p/18220974

相关文章

  • 【python数据结构4】基于栈结构的简单括号匹配
    我们现在把注意力转向使用栈解决真正的计算机问题。你会这么写算术表达式(5+6)*(7+8)/(4+3)其中括号用于命令操作的执行。你可能也有一些语言的经验,如Lisp的构造(defunsquare(n)(*nn))这段代码定义了一个名为square的函数,它将返回参数的n的平方。Lisp......
  • 基于Python与水星二代摄像头的二次开发
    第一章Videocapture的正确使用大家好!关于摄像头的基本调用,相信大家以及初步学会了。我们买来这个摄像头,本来就是想着自己使用,进行二次开发的。但是大家根据OpenCV的调用函数Videocapture(),发现根本无法调用,这是为什么?首先,判断外接摄像头能否调用,我们有两个非常简单的方法:方......
  • 【Python Cookbook】S01E03 找到最大最小的N个元素
    目录问题解决方案讨论问题如何在一个集合中找到最大或最小的N个元素?解决方案使用heapq模块。pipinstallheapqheapq模块中,有nlargest()以及nsmallest()两个函数:importheapqnums=[1,8,23,2,7,-4,8,18,42,37]print(heapq.nlargest(3,n......
  • python处理EXCEL
    python处理EXCEL在Python中,有多个库可以用来操作Excel文件。其中比较常用的有openpyxl,pandas,xlsxwriter以及xlwings。下面我将分别介绍这些库及其使用方法。一、openpyxl安装pipinstallopenpyxl示例代码fromopenpyxlimportWorkbook,load_workbookfromopenp......
  • Python正则表达式
    语法关于正则表达式的相关知识,大家可以阅读一篇非常有名的博客叫《正则表达式30分钟入门教程》,读完这篇文章后你就可以看懂下面的表格,这是我们对正则表达式中的一些基本符号进行的扼要总结。符号解释示例说明.匹配任意字符b.t可以匹配bat/but/b#t/b1t等\w匹配字母/......
  • python之生成xmind
    今天为啥要说这个呢,因为前几天做接口测试,还要写测试用例,我觉得麻烦,所以我就用了python里面xmind的插件。自动生成了测试用例,数据来源是json。......
  • ChatGPT学习Python系列之Python装饰器
    ChatGPT学习Python系列之Python装饰器网上查询Python装饰器相关资料,质量层次不齐,通过问答形式利用ChatGPT3.5学习了Python装饰器相关的概念及示例,GPT给出的解答和示例代码质量非常高,总结如下。1.什么是python装饰器Python的装饰器是一种功能强大的语法,允许在不修改原始函数代......
  • python处理EXCEL
    !https://zhuanlan.zhihu.com/p/700537143python处理EXCEL在Python中,有多个库可以用来操作Excel文件。其中比较常用的有openpyxl、pandas,以及xlsxwriter。下面我将分别介绍这些库及其使用方法。一、openpyxl安装pipinstallopenpyxl示例代码fromopenpyxlimportWorkbo......
  • Python lambda函数
    Pythonlambda函数Python中的lambda函数,用于创建简洁的匿名函数。Lambda函数通常用于在需要函数作为参数的上下文中,以及在需要临时定义简单函数的地方。下面是一些关于lambda函数的基本知识和用法:1.lambda函数的基本语法lambdaarguments:expressionlambda关键字用于声明......
  • 用Python写一个热点事件追踪的算法
     要编写一个热点事件追踪的算法,首先需要明确算法的主要目标和所需的数据。在这个例子中,我们将基于微博的热度(如点赞数、转发数和评论数)来追踪热点事件。以下是一个简单的Python算法,仅供参考: 1.导入所需库 ```pythonimportrequestsfrombs4importBeautifulSoupimp......