MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python正则表达式基础入门

2023-05-147.7k 阅读

什么是正则表达式

正则表达式(Regular Expression),又称规则表达式,是一种用于描述、匹配和处理字符串的强大工具。在Python中,正则表达式模块re提供了一系列函数来操作正则表达式。正则表达式本质上是一种小型的、高度专业化的编程语言,它可以用来定义字符串的搜索模式。

正则表达式的作用

  1. 数据验证:在处理用户输入时,需要确保输入的数据符合特定的格式,比如邮箱地址、电话号码等。例如,验证邮箱地址是否合法,使用正则表达式可以快速判断输入字符串是否符合邮箱格式。
  2. 数据提取:从大量文本中提取特定格式的数据。比如从一篇网页代码中提取所有的链接,正则表达式能够精准定位并提取出符合链接格式的字符串。
  3. 文本替换:将文本中符合特定模式的字符串替换为其他内容。例如将一篇文章中的所有手机号码替换为特定的掩码形式,以保护隐私。

Python中的re模块

Python通过内置的re模块来支持正则表达式操作。在使用re模块之前,需要先导入它:

import re

re模块的常用函数

  1. re.search():在字符串中搜索匹配正则表达式的第一个位置,返回一个匹配对象,如果没有匹配则返回None
import re
text = "Python is great, Python can be used for data analysis"
match = re.search(r'Python', text)
if match:
    print("Match found:", match.group())
else:
    print("No match")

在上述代码中,r'Python'是正则表达式,r前缀表示这是一个原始字符串,其中的反斜杠不会被解释为转义字符。re.search()函数在text字符串中搜索Python,如果找到则打印匹配的内容。

  1. re.findall():在字符串中找到所有匹配正则表达式的子串,并以列表形式返回。
import re
text = "Python is great, Python can be used for data analysis"
matches = re.findall(r'Python', text)
print("Matches:", matches)

这里re.findall()函数返回了text字符串中所有出现的Python子串组成的列表。

  1. re.sub():将字符串中所有匹配正则表达式的子串替换为指定的字符串。
import re
text = "Python is great, Python can be used for data analysis"
new_text = re.sub(r'Python', 'Java', text)
print("New text:", new_text)

上述代码将text字符串中的所有Python替换为Java

正则表达式的基本语法

字符匹配

  1. 普通字符:普通字符直接匹配自身。例如,正则表达式abc会匹配字符串中出现的abc子串。
import re
text = "abcdef"
match = re.search(r'abc', text)
if match:
    print("Match found:", match.group())
else:
    print("No match")
  1. 元字符:具有特殊含义的字符。常见的元字符有^$.*+?{}[]()|等。
    • ^:匹配字符串的开头。例如,^Python表示匹配以Python开头的字符串。
import re
text1 = "Python is fun"
text2 = "Java is fun"
match1 = re.search(r'^Python', text1)
match2 = re.search(r'^Python', text2)
if match1:
    print("Match in text1:", match1.group())
else:
    print("No match in text1")
if match2:
    print("Match in text2:", match2.group())
else:
    print("No match in text2")
- **`$`**:匹配字符串的结尾。例如,`fun$`表示匹配以`fun`结尾的字符串。
import re
text1 = "Python is fun"
text2 = "Python is funny"
match1 = re.search(r'fun$', text1)
match2 = re.search(r'fun$', text2)
if match1:
    print("Match in text1:", match1.group())
else:
    print("No match in text1")
if match2:
    print("Match in text2:", match2.group())
else:
    print("No match in text2")
- **`.`**:匹配除换行符`\n`之外的任意单个字符。例如,`a.c`可以匹配`abc`、`aec`等。
import re
text = "abc aec"
matches = re.findall(r'a.c', text)
print("Matches:", matches)

字符类

  1. 方括号[]:用于定义字符类,表示匹配方括号内的任意一个字符。例如,[abc]表示匹配abc中的任意一个字符。
import re
text = "abcdef"
matches = re.findall(r'[abc]', text)
print("Matches:", matches)
  1. 范围表示:在方括号内可以使用-表示字符范围。例如,[a - z]表示匹配任意小写字母,[0 - 9]表示匹配任意数字。
import re
text = "a1b2c3"
matches1 = re.findall(r'[a - z]', text)
matches2 = re.findall(r'[0 - 9]', text)
print("Letter matches:", matches1)
print("Number matches:", matches2)
  1. 否定字符类:在方括号内开头加上^表示否定字符类,即匹配不在方括号内的任意字符。例如,[^a - z]表示匹配不是小写字母的字符。
import re
text = "a1B"
matches = re.findall(r'[^a - z]', text)
print("Matches:", matches)

量词

  1. *:表示前面的字符可以出现0次或多次。例如,ab*可以匹配aababb等。
import re
text = "a ab abb"
matches = re.findall(r'ab*', text)
print("Matches:", matches)
  1. +:表示前面的字符可以出现1次或多次。例如,ab+可以匹配ababb等,但不匹配a
import re
text = "a ab abb"
matches = re.findall(r'ab+', text)
print("Matches:", matches)
  1. ?:表示前面的字符可以出现0次或1次。例如,ab?可以匹配aab
import re
text = "a ab"
matches = re.findall(r'ab?', text)
print("Matches:", matches)
  1. {n}:表示前面的字符必须出现n次。例如,a{3}表示匹配aaa
import re
text = "aa aaa aaaa"
matches = re.findall(r'a{3}', text)
print("Matches:", matches)
  1. {n,}:表示前面的字符至少出现n次。例如,a{3,}表示匹配aaaaaaa等。
import re
text = "aa aaa aaaa"
matches = re.findall(r'a{3,}', text)
print("Matches:", matches)
  1. {n,m}:表示前面的字符至少出现n次,最多出现m次。例如,a{2,4}表示匹配aaaaaaaaa
import re
text = "aa aaa aaaa aaaaa"
matches = re.findall(r'a{2,4}', text)
print("Matches:", matches)

分组与捕获

  1. 圆括号():用于分组,可以将多个字符作为一个整体进行操作,并且可以捕获匹配的内容。例如,(ab)+表示匹配ab出现1次或多次。
import re
text = "ab abab"
matches = re.findall(r'(ab)+', text)
print("Matches:", matches)
  1. 捕获组:圆括号内的内容形成捕获组,可以通过匹配对象的方法获取捕获组的内容。
import re
text = "John: 25"
match = re.search(r'(\w+): (\d+)', text)
if match:
    name = match.group(1)
    age = match.group(2)
    print("Name:", name)
    print("Age:", age)

在上述代码中,(\w+)(\d+)是两个捕获组,match.group(1)获取第一个捕获组匹配的内容(即名字),match.group(2)获取第二个捕获组匹配的内容(即年龄)。

非捕获组

在圆括号内开头加上?:表示非捕获组,它不会捕获匹配的内容。例如,(?:ab)+表示匹配ab出现1次或多次,但不捕获ab

import re
text = "ab abab"
matches = re.findall(r'(?:ab)+', text)
print("Matches:", matches)

正则表达式的高级应用

零宽断言

  1. 正向前瞻断言(?=pattern):断言当前位置之后的字符串匹配pattern,但不包含pattern本身。例如,Python(?= is great)表示匹配Python,但前提是Python后面跟着 is great
import re
text = "Python is great"
match = re.search(r'Python(?= is great)', text)
if match:
    print("Match found:", match.group())
else:
    print("No match")
  1. 负向前瞻断言(?!pattern):断言当前位置之后的字符串不匹配pattern。例如,Python(?! is great)表示匹配Python,但前提是Python后面不跟着 is great
import re
text1 = "Python is easy"
text2 = "Python is great"
match1 = re.search(r'Python(?! is great)', text1)
match2 = re.search(r'Python(?! is great)', text2)
if match1:
    print("Match in text1:", match1.group())
else:
    print("No match in text1")
if match2:
    print("Match in text2:", match2.group())
else:
    print("No match in text2")
  1. 正向后顾断言(?<=pattern):断言当前位置之前的字符串匹配pattern,但不包含pattern本身。例如,(?<=is )great表示匹配great,但前提是great前面是is
import re
text = "Python is great"
match = re.search(r'(?<=is )great', text)
if match:
    print("Match found:", match.group())
else:
    print("No match")
  1. 负向后顾断言(?<!pattern):断言当前位置之前的字符串不匹配pattern。例如,(?<!is )great表示匹配great,但前提是great前面不是is
import re
text1 = "Python great"
text2 = "Python is great"
match1 = re.search(r'(?<!is )great', text1)
match2 = re.search(r'(?<!is )great', text2)
if match1:
    print("Match in text1:", match1.group())
else:
    print("No match in text1")
if match2:
    print("Match in text2:", match2.group())
else:
    print("No match in text2")

贪婪与非贪婪匹配

  1. 贪婪匹配:默认情况下,量词(如*+?{n,}{n,m})是贪婪的,即尽可能多地匹配字符。例如,a.*b会匹配从a开始到最后一个b之间的所有字符。
import re
text = "aabab"
match = re.search(r'a.*b', text)
if match:
    print("Greedy match:", match.group())
  1. 非贪婪匹配:在量词后面加上?可以使其变为非贪婪匹配,即尽可能少地匹配字符。例如,a.*?b会匹配从a开始到第一个b之间的字符。
import re
text = "aabab"
match = re.search(r'a.*?b', text)
if match:
    print("Non - greedy match:", match.group())

正则表达式的编译

re模块提供了re.compile()函数,可以将正则表达式编译成正则表达式对象。编译后的对象可以多次使用,提高效率。

import re
pattern = re.compile(r'Python')
text = "Python is great, Python can be used for data analysis"
matches = pattern.findall(text)
print("Matches:", matches)

上述代码先将正则表达式Python编译成pattern对象,然后使用该对象的findall()方法在字符串中查找匹配项。

正则表达式的错误处理

在编写正则表达式时,可能会出现语法错误。re模块会抛出re.error异常。例如,以下代码中错误地使用了量词:

import re
try:
    re.search(r'a*?', 'abc')
except re.error as e:
    print("Error:", e)

在实际应用中,应该使用try - except块来捕获并处理这些异常,以确保程序的稳定性。

实际案例分析

验证邮箱地址

import re


def validate_email(email):
    pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9 -]+\.[a-zA-Z0-9-.]+$'
    if re.match(pattern, email):
        return True
    return False


email1 = "test@example.com"
email2 = "test.example.com"
print(validate_email(email1))
print(validate_email(email2))

在上述代码中,^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9 -]+\.[a-zA-Z0-9-.]+$这个正则表达式用于验证邮箱地址。它的开头^和结尾$确保整个字符串都匹配邮箱格式。[a-zA-Z0-9_.+-]+匹配邮箱用户名部分,@匹配@符号,[a-zA-Z0-9 -]+匹配域名部分,\.匹配实际的点号,[a-zA-Z0-9-.]+匹配顶级域名部分。

提取网页链接

import re


def extract_links(html):
    pattern = r'href="(.*?)"'
    return re.findall(pattern, html)


html = '<a href="https://www.example.com">Example</a><a href="https://www.google.com">Google</a>'
links = extract_links(html)
print(links)

这里r'href="(.*?)"'这个正则表达式用于从HTML代码中提取链接。href="匹配href="字符串,(.*?)使用非贪婪匹配捕获双引号内的链接内容。

通过以上内容,你应该对Python正则表达式有了较为全面的了解,从基础语法到高级应用,再到实际案例分析,希望这些知识能帮助你在处理字符串相关任务时更加得心应手。