您的位置:

Python正则表达式:高效匹配文本

在我们平时的工作和学习中,常常需要对字符串进行处理。而正则表达式则是一种强大的字符串匹配工具,可以用于字符串的查找、替换、截取等操作。

一、正则表达式基础

正则表达式是由一系列字符和特殊字符组成的模式,用于描述字符串的特征。常用的正则表达式元字符有:

  • .:匹配除换行符以外的任意字符
  • \d:匹配数字字符,也可以用[0-9]表示
  • \w:匹配字母、数字和下划线,也可以用[a-zA-Z0-9_]表示
  • \s:匹配空白字符,包括空格、制表符、换行符等
  • []:用于指定匹配的字符集合,比如[aeiou]匹配元音字母
  • ^:匹配开头,比如^hello匹配以hello开头的字符串
  • $:匹配结尾,比如world$匹配以world结尾的字符串
  • *:匹配任意次,包括0次
  • +:匹配至少一次
  • ?:匹配0次或1次
  • {m,n}:匹配m至n次,包括m和n

下面是一个简单的示例,利用正则表达式匹配出一个字符串中的数字:

 import re
 str = 'There are 3 apples and 5 oranges.'
 pattern = r'\d+'
 result = re.findall(pattern, str)
 print(result)  # ['3', '5']

以上代码使用\d+这个正则表达式模式来查找字符串中的数字,并返回一个列表。如果使用re.search()函数,则会返回第一个匹配的结果。

二、正则表达式高级应用

正则表达式不仅可以用来进行基本的匹配,还可以进行分组、反向引用、零宽断言等高级操作。

1. 分组

分组可以将正则表达式中的一部分提取出来,方便后续对其进行操作。分组使用圆括号()进行表示。比如匹配一段文本中的中英文名字:

 import re
 text = 'My name is Jack, 你叫什么名字?'
 pattern = r'My name is (\w+), (.+)\?'
 match = re.search(pattern, text)
 if match:
    print('My name is', match.group(1))
    print('What is your name?', match.group(2))

以上代码中,(\w+)表示将英文名字进行分组,(.+)表示将中文名字进行分组,然后使用match.group()方法获取分组结果。

2. 反向引用

反向引用可以在正则表达式中引用前面的分组结果。它使用\数字(?P<name>)进行表示,其中\<数字>表示引用数字代表的分组结果,(?P<name>)则可以为分组指定一个名字。

比如,使用正则表达式寻找重复的单词:

 import re
 text = 'I like coding, coding is fun. What do you like?'
 pattern = r'\b(\w+)\b\s+\1\b'
 matches = re.findall(pattern, text)
 print(matches)  # ['coding']

以上代码中,(\w+)将一个单词进行分组,\s+匹配任意长度的空格,\1则表示引用前面的分组结果。它的含义是,匹配重复的单词,即两个相同的单词之间有任意长度的空格。

3. 零宽断言

零宽断言是指在匹配字符串的时候,只匹配符合某种条件的字符串,而不将该条件字符串包含其中。常用的零宽断言有:正向先行断言(?=pattern)、正向后行断言(?<=pattern)、负向先行断言(?!pattern)和负向后行断言(?<!pattern)

比如,判断一个字符串是否包含数字和字母:

 import re
 text = 'abc123'
 pattern1 = r'(?=.*\d)(?=.*[a-zA-Z])'
 pattern2 = r'[a-zA-Z0-9]{6,}'
 match1 = re.search(pattern1, text)
 match2 = re.search(pattern2, text)
 if match1 and match2:  
    print('The text contains letters and numbers.')

以上代码中,(?=.*\d)(?=.*[a-zA-Z])分别表示要求字符串中包含数字和字母,[a-zA-Z0-9]{6,}则表示要求字符串中至少有6个字母和数字。

三、应用实例

正则表达式可以应用于很多场景,比如爬虫、文本处理、数据清洗等。下面是一些常见的应用实例。

1. 爬虫

在爬虫中,我们需要从网页中提取有用的信息,又需要快速、准确地将无用信息滤掉。正则表达式可以帮助我们完成这个任务。

 import re
 import requests
 url = 'https://www.baidu.com'
 html = requests.get(url).text
 pattern = r''
 result = re.findall(pattern, html)
 for link in result:
    print(link)

以上代码中,<a href="(https?:\/\/.*?)".*?>表示匹配所有标签中的URL。这样我们就可以从网页中提取出所有的链接。

2. 文本处理

正则表达式在文本处理中的应用也是非常广泛的。比如,在处理日志文件时,我们需要将其中的IP地址进行提取,正则表达式可以轻松实现。

 import re
 log = '127.0.0.1 - - [01/May/2022:08:34:12 +0800] "GET / HTTP/1.1" 200 1234'
 pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
 result = re.search(pattern, log)
 if result:
    print(result.group())

以上代码中,\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}可以匹配IP地址。正则表达式可以解决很多文本处理问题,大大提高了工作效率。

3. 数据清洗

在数据清洗中,正则表达式也扮演着重要的角色。比如,在清洗电话号码数据时,我们可以使用正则表达式将格式不正确的号码过滤掉或者进行格式转换。

 import re
 phone = '0086-13812345678'
 pattern1 = r'^\d{1,4}-\d{7,8}$'
 pattern2 = r'^0086-(\d{11})$'
 if re.match(pattern1, phone):
    print('The phone number is in the correct format.')
 match = re.match(pattern2, phone)
 if match:
    print('The corrected phone number is +86-', match.group(1))

以上代码中,^\d{1,4}-\d{7,8}$表示匹配以区号开头,后接7位或8位号码的电话号码格式。而^0086-(\d{11})$则表示将0086开头的电话号码转换成+86-XXXXXXXXXXX的格式。