一文搞定python正则表达式

概念&作用

正则表达式是一种用来描述文本模式的工具,它可以帮助你在字符串中查找匹配替换符合某种模式的文本。通过使用正则表达式,你可以定义一些规则,然后在文本中查找符合这些规则的内容。正则表达式可以用于各种编程语言和文本处理工具中,例如Python、JavaScript、Perl等。

python中的正则表达式

在python中,内置的 re 模块提供了对正则表达式的支持,这使得在 Python 中处理文本数据变得非常方便和高效。正则表达式在 Python 中非常有用,主要是因为re模块具有强大的模式匹配功能、文本处理的灵活性、替换和修改文本的能力以及Python 的易用性和广泛应用。

基础构成

字符

正则表达式中的字符可以是字母、数字或符号,它们代表自身字符。例如,a 匹配字符 "a"。

元字符

元字符是具有特殊含义的字符,它们不仅仅代表自身字符。一些常见的元字符包括

元字符作用含义
.匹配除换行符以外的任意字符。
^匹配字符串的开头。
$匹配字符串的结尾。
\d匹配任意一个数字字符,相当于 [0-9]
\D匹配任意一个非数字字符,相当于 [^0-9]
\w匹配任意一个字母、数字或下划线字符,相当于 [a-zA-Z0-9_]
\W匹配任意一个非字母、数字或下划线字符,相当于 [^a-zA-Z0-9_]
\s匹配任意一个空白字符,包括空格、制表符、换行符等
\S匹配任意一个非空白字符
\b匹配单词边界,即字与空格之间的位置
\B匹配非单词边界
*匹配前一个字符的零个或多个。
+匹配前一个字符的一个或多个。
?匹配前一个字符的零个或一个。
[]匹配方括号内的任意一个字符。例如,[aeiou]匹配任意一个元音字母。
|匹配两个或多个模式之一。
()用于创建捕获组,可以对匹配的内容进行分组。
量词

量词用于指定匹配字符重复出现的次数,常见的量词包括:

量词作用含义
{m}精确匹配前一个字符出现 m 次
{m,n}匹配前一个字符出现至少 m 次,最多 n 次
{m,}匹配前一个字符出现至少 m 次
*匹配前一个字符的零个或多个
+匹配前一个字符的一个或多个
?匹配前一个字符的零个或一个
原始字符串

在Python中,r字符串是一种特殊的字符串表示形式,被称为原始字符串(raw string)。在原始字符串中,反斜杠 \ 不会被解释为转义字符,而是作为普通字符对待。这意味着在原始字符串中,反斜杠后面的字符会保持原样,不会被转义。

例如,在普通字符串中,要表示一个Windows文件路径,你需要使用双反斜杠来转义,如下所示:

path = "C:\\Users\\username\\Documents\\file.txt"

而在原始字符串中,你可以直接写成:

path = r"C:\Users\username\Documents\file.txt"

这使得处理一些特殊字符串,如正则表达式模式或文件路径,更加方便,因为你无需担心转义字符带来的影响。

re模块

Python 的正则表达式模块 re 提供了一系列功能,让你可以在字符串中进行模式匹配、查找和替换等操作。你提到的 re.match()re.search()re.findall()re.sub()re.compile() 是其中常用的几个函数。

re.match

re.match(pattern, string, flags=0)尝试从字符串的开头匹配一个模式。如果字符串开头匹配成功,则返回一个匹配对象;否则返回 None。这意味着它只匹配字符串的开头位置。

import re

pattern = r'hello'
string = 'hello world'
match_obj = re.match(pattern, string)
if match_obj:
    print("Match found:", match_obj.group())
else:
    print("No match found")

# Match found: hello
re.search

re.search(pattern, string, flags=0)re.match(pattern, string, flags=0)类似,但是它在整个字符串中搜索匹配项,返回第一个匹配到的对象。这意味着它可以匹配字符串的任意位置。

import re

pattern = r'world'
string = 'hello world'
search_obj = re.search(pattern, string)
if search_obj:
    print("Match found:", search_obj.group())
else:
    print("No match found")

# Match found: world
re.findall

re.findall(pattern, string, flags=0)在字符串中找到所有匹配项,并以列表的形式返回。它不同于 re.match()re.search(),它不返回匹配对象,而是直接返回匹配的字符串列表。

import re

pattern = r'lo'
string = 'hello world'
matches = re.findall(pattern, string)
print("Matches found:", matches)

# Matches found: ['lo']
re.sub

re.sub(pattern, repl, string, count=0, flags=0)用来在字符串中查找匹配项,并替换为指定的字符串。它返回替换后的新字符串。

import re

pattern = r'world'
replacement = 'universe'
string = 'hello world'
new_string = re.sub(pattern, replacement, string)
print("New string:", new_string)

# New string: hello universe
re.compile

re.compile(pattern, flags=0)是Python 中用于预编译正则表达式模式的函数。这个函数接受一个正则表达式作为参数,并返回一个正则表达式对象,这个对象可以被用来执行匹配操作。这个函数诸多优点:

  • 提高效率: 编译后的正则表达式对象可以在多次使用时提高匹配效率。因为编译后的对象已经将正则表达式模式编译为内部数据结构,避免了每次匹配都要重新解析模式的开销。

  • 可重用性: 编译后的正则表达式对象可以在多个地方使用,而不需要每次都重新编译正则表达式模式,提高了代码的可重用性。

  • 简化代码: 将常用的正则表达式模式预先编译,可以简化代码,使代码更加清晰易懂。

import re

# 编译正则表达式模式
pattern = re.compile(r'\d{3}-\d{3}-\d{4}')

# 使用编译后的对象进行匹配操作
result = pattern.search("John's phone number is 123-456-7890.")
if result:
   print("Phone number found:", result.group())
else:
   print("Phone number not found.")

# Phone number found: 123-456-7890
flag的可选值
  • re.IGNORECASEre.I: 忽略大小写匹配。

  • re.MULTILINEre.M: 多行匹配,使 ^$ 匹配字符串的每行的开头和结尾,而不是整个字符串的开头和结尾。

  • re.DOTALLre.S: 让 . 匹配任何字符,包括换行符。

  • re.UNICODEre.U: 使 \w, \W, \b, \B, \d, \D, \s, \SUnicode 字符集合匹配。

  • re.ASCII: 使 \w, \W, \b, \B, \d, \D, \s, \SASCII 字符集合匹配。

  • re.VERBOSEre.X: 忽略空白和注释,使得更易读的正则表达式能够被编写。

正/反向前瞻

正向前瞻(Positive Lookahead):正向前瞻用 (?=…) 表示,它指定了一个条件,在匹配位置的右侧必须满足这个条件才能匹配成功。但匹配的位置本身不会被包含在匹配结果中。

反向前瞻(Negative Lookahead):反向前瞻用 (?!…) 表示,它指定了一个条件,在匹配位置的右侧必须不满足这个条件才能匹配成功。同样,匹配的位置本身不会被包含在匹配结果中。

接下来演示一下,假设我们要匹配一个字符串中的所有数字,但是要排除包含小数点的数字。我们可以使用正向前瞻来实现这个匹配:

import re

# 匹配所有不包含小数点的数字
pattern = r'\d+(?!\.)'
text = "123 456 7.89 10"

matches = re.findall(pattern, text)
print(matches)

# ['123', '456', '10']

在这个示例中,r'\d+(?!\.)' 匹配的是一串数字 \d+,但是它的右侧不能跟着一个小数点 (?!\.),这样就排除了包含小数点的数字。

反向前瞻也可以用来排除某些特定情况的匹配。例如,假设我们要匹配所有不是以字母 "a" 开头的单词:

import re

# 匹配所有不以字母 "a" 开头的单词
pattern = r'\b(?!a)\w+\b'
text = "apple banana orange"

matches = re.findall(pattern, text)
print(matches)  
# ['banana', 'orange']

在这个示例中,r'\b(?!a)\w+\b' 匹配的是一个单词,但是它的左侧不能以字母 "a" 开头 (?!a),这样就排除了以 "a" 开头的单词 "apple"。

捕获组和非捕获组的概念

在正则表达式中,捕获组和非捕获组是用来对匹配的文本进行分组和提取的工具, 比如Django/Flask等框架的url路由匹配就是用了这个。

捕获组:捕获组用括号 ( ) 表示,它可以将匹配的文本分组并保存到一个单独的组中,以便后续引用或提取。捕获组可以在整个正则表达式中通过反向引用(backreference)或在匹配结果中进行访问。

非捕获组:非捕获组也用括号 ( ) 表示,但是在左括号后紧跟着一个问号和冒号 (?: ),它用于对文本进行分组,但不会在匹配结果中保存分组的内容,也不会创建一个新的捕获组。非捕获组通常用于提高正则表达式的效率,因为它不会占用额外的内存来存储匹配结果。

接下来演示一下, 假设我们有一个包含邮箱地址的字符串,我们想从中提取用户名和域名部分。我们可以使用捕获组来实现:

import re

# 匹配邮箱地址的正则表达式
pattern = r'(\w+)@(\w+\.\w+)'

text = "jeff@xmishu.com, alice@baidu.com"

# 使用捕获组提取用户名和域名
matches = re.findall(pattern, text)
for match in matches:
    username, domain = match
    print("Username:", username)
    print("Domain:", domain)

在这个示例中,(\w+)(\w+\.\w+) 分别是两个捕获组,用来提取用户名和域名。re.findall() 函数会返回一个列表,其中每个元素是一个包含用户名和域名的元组。通过遍历这个列表,我们可以轻松地获取用户名和域名部分。

实际应用

正则表达式在python应用中非常广泛,它能辅助我们高效地处理很多问题

  • 数据提取(网页数据采集等)

  • 文本处理(数据清洗、格式化入库等)

  • web表单中用户输入内容验证(邮箱密码格式验证等)。

注意事项

  • 预编译正则表达式:如果你要在多个地方使用相同的正则表达式,可以使用re.compile()预先编译它,以提高匹配效率,生产环境中很有用。

  • 选择最适合的函数:Python的re模块提供了多个函数用于正则表达式操作,如re.match()re.search()re.findall()等。根据需求选择最适合的函数,以避免不必要的性能开销。

  • 使用非贪婪匹配:在量词后面加上?可以将匹配模式变为非贪婪模式,尽可能少地匹配字符。例如,*?+???

  • 避免过度使用.:.可以匹配任意一个字符,但在某些情况下可能会导致性能下降。如果可能,尽量使用更具体的字符集或模式来限制匹配范围。

  • 使用原始字符串:在编写正则表达式时,最好使用原始字符串(以r开头),以避免不必要的转义,提高代码可读性。

  • 使用字符类:字符类(如[0-9][a-zA-Z])比单个字符更有效率,因为它们允许正则引擎更快地确定是否匹配。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值