python | Python 正则表达式实战:文本清洗常用模式

本文来源公众号“python”,仅用于学术分享,侵权删,干货满满。

原文链接:Python 正则表达式实战:文本清洗常用模式

在数据处理领域,文本清洗是数据预处理的关键环节。原始文本常包含冗余的特殊字符、格式错误、无效符号或敏感信息,例如网页中的HTML标签、日志文件中的乱码、用户输入的表情符号等。正则表达式(Regular Expression)作为文本处理的强大工具,能通过定义模式快速匹配、提取、替换目标文本,极大提升清洗效率。Python的re模块提供了完整的正则表达式支持,结合其简洁的语法和灵活的API,成为处理文本清洗任务的首选方案。

文本清洗常用正则模式

1. 基础字符匹配与替换

(1)匹配任意字符:.与字符集[]
  • . 匹配除换行符外的任意单个字符(如需匹配换行,需设置re.DOTALL标志)。

  • [abc] 匹配a、b、c中的任意一个字符,支持范围匹配(如[a-z]匹配小写字母,[0-9]匹配数字)。

  • [^abc] 反向匹配,即不匹配a、b、c中的任意一个字符。

应用场景:去除文本中的标点符号或特殊字符(如!@#$%^&*())。
正则模式[^\w\s](匹配非字母、数字、空格的字符,\w等价于[a-zA-Z0-9_]\s匹配空白符)。

(2)边界匹配:^$
  • ^ 匹配字符串开头,$匹配字符串结尾,确保模式仅作用于完整字段。

    • 示例:^\d+$ 仅匹配全由数字组成的字符串(如"12345"),避免匹配包含数字的混合文本(如"abc123")。

2. 重复匹配:量词限定符

(1)基础量词
  • *:匹配前一个字符0次或多次(如a*匹配空字符串、"a""aa"等)。

  • +:匹配前一个字符1次或多次(如a+至少匹配1个a)。

  • ?:匹配前一个字符0次或1次(用于处理可选内容,如colou?r匹配"color""colour")。

(2)精确量词
  • {n}:匹配前一个字符恰好n次(如\d{3}匹配3位数字)。

  • {n,}:匹配前一个字符至少n次(如\d{8,}匹配8位以上数字)。

  • {n,m}:匹配前一个字符n到m次(如\d{4,6}匹配4-6位数字)。

应用场景:清洗连续重复字符(如用户输入的"好好好好笑"转为"好笑")。
正则模式(.)\1+(捕获任意字符(.),并匹配其连续重复1次以上\1+\1为反向引用,指向第一个分组)。

3. 分组与捕获:()

通过()将模式分组,可提取匹配结果中的特定部分(如从"2023-10-01"中提取年、月、日)。

  • 示例(\d{4})-(\d{2})-(\d{2}) 可捕获3个分组,分别对应年、月、日。

  • 反向引用\1\2等表示对分组内容的引用(如匹配重复单词\b(\w+)\s+\1\b,检测"hello hello")。

4. 特殊字符转义:\

当需要匹配正则表达式中的特殊字符(如$([等),需在前面添加反斜杠\

  • 示例:匹配字符串中的"$100",正则应为\$100$是特殊字符,需转义)。

典型文本清洗场景

1. 去除文本中的特殊字符与空白符

清洗用户输入的文本,保留字母、数字、中文及必要空格,去除其他特殊符号(如标点、表情符号、控制字符)。

import re  

def clean_special_chars(text: str) -> str:
    # 定义需要保留的字符:字母(大小写)、数字、中文、空格  
    # 正则模式:匹配所有非保留字符(使用反向字符集[^a-zA-Z0-9\u4e00-\u9fa5\s])  
    pattern = r'[^a-zA-Z0-9\u4e00-\u9fa5\s]'
    # 使用re.sub替换匹配内容为空字符串  
    cleaned_text = re.sub(pattern, '', text)  
    # 额外处理连续空格(替换为单个空格)  
    cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip()  
    return cleaned_text  

# 示例输入  
dirty_text = "Hello!这是一段测试文本,包含特殊符号@#$,还有表情😊和多余  空格。"
cleaned_result = clean_special_chars(dirty_text)  
print("清洗后:", cleaned_result)  
清洗后: Hello 这是一段测试文本 包含特殊符号 还有表情 和多余 空格
  • \u4e00-\u9fa5 匹配中文字符(Unicode范围)。

  • \s+ 匹配连续空白符(包括空格、制表符、换行符),替换为单个空格。

  • strip() 去除文本首尾的空白符。

2. 提取结构化信息:从日志中解析时间戳与错误码

从服务器日志"[2023-10-01 14:30:45] ERROR: Code 404 - File not found"中提取时间戳(2023-10-01 14:30:45)和错误码(404)。

def parse_log(log: str) -> tuple | None:  
    # 正则模式:分组捕获时间戳和错误码  
    pattern = r'\[([\d\- :]+)\]\s+ERROR:\s+Code\s+(\d+)'
    match = re.search(pattern, log)  
    if match:  
        timestamp = match.group(1)  # 第一个分组(时间戳)  
        error_code = match.group(2)  # 第二个分组(错误码)  
        return timestamp, error_code  
    returnNone

# 示例日志  
log_entry = "[2023-10-01 14:30:45] ERROR: Code 404 - File not found"
parsed_result = parse_log(log_entry)  
print("解析结果:", parsed_result)  
解析结果: ('2023-10-01 14:30:45', '404')  
  • [\d\- :]+ 匹配数字、连字符、空格、冒号,用于捕获时间戳(-在字符集中需放在末尾或转义,此处位于中间,需写成\-,但示例中直接使用-未报错,因在字符集内部,-表示范围,若需匹配字面量-,应放在开头或结尾,或转义,此处为简化写法,实际建议使用\-避免歧义)。

  • re.search() 返回第一个匹配项,group(n)获取第n个分组内容。

3. 清洗HTML标签与富文本格式

去除网页爬取文本中的HTML标签(如<p><div><span class="text">),仅保留纯文本内容。

def clean_html_tags(text: str) -> str:  
    # 正则模式:匹配<...>形式的HTML标签(包括自闭合标签和带属性的标签)  
    # 使用非贪婪匹配`?`避免匹配跨越多标签  
    pattern = r'<.*?>'
    # 额外处理特殊转义字符(如&nbsp;、&amp;)  
    text = re.sub(r'&nbsp;', ' ', text)  
    text = re.sub(r'&amp;', '&', text)  
    cleaned_text = re.sub(pattern, '', text).strip()  
    return cleaned_text  

# 示例HTML文本  
html = "<div class='content'><p>这是一段包含&nbsp;HTML标签的文本&amp;特殊符号。</p></div>"
cleaned_html = clean_html_tags(html)  
print("清洗后:", cleaned_html)  
清洗后: 这是一段包含 HTML标签的文本&特殊符号。  
  • <.*?> 匹配以<开头、>结尾的任意内容,?表示非贪婪匹配(尽可能少匹配字符,避免跨越多标签)。

  • 先处理&nbsp;(空格实体)和&amp;(&符号转义),再统一去除标签,确保文本可读性。

复杂场景清洗策略

1. 社交媒体文本清洗(去除表情、URL、话题标签)

清洗微博、Twitter等平台的用户评论,去除表情符号、URL链接、话题标签(如#热点话题@用户名),保留纯文本内容。

def clean_social_media(text: str) -> str:  
    # 1. 去除URL(支持http/https/ftp,以及常见域名后缀)  
    url_pattern = r'https?://[^\s]+|www\.[^\s]+'
    # 2. 去除话题标签(#开头的内容)和@提及  
    tag_pattern = r'#\w+|@\w+'
    # 3. 去除表情符号(匹配Unicode表情范围,需覆盖常见平台)  
    emoji_pattern = r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF]'
    # 4. 去除连续重复字符(如“哈哈哈”转为“哈”)  
    repeat_pattern = r'(.)\1+'
    cleaned_text = re.sub(url_pattern, '', text)  
    cleaned_text = re.sub(tag_pattern, '', cleaned_text)  
    cleaned_text = re.sub(emoji_pattern, '', cleaned_text)  
    cleaned_text = re.sub(repeat_pattern, r'\1', cleaned_text)  # 保留单个字符  
    return cleaned_text.strip()  

# 示例输入  
social_text = "今天天气超好😊!打卡#周末去哪儿 @好友 查看攻略:https://example.com 哈哈哈哈~"
cleaned_social = clean_social_media(social_text)  
print("清洗后:", cleaned_social)  
清洗后: 今天天气超好!打卡 查看攻略: 哈哈~  
  • 表情符号的Unicode范围需根据实际场景调整,可通过在线工具(如Unicode Emoji Chart)获取完整范围。

  • 组合使用多个正则表达式,按“从复杂到简单”的顺序处理(先处理URL、标签,再处理短符号)。

2. 处理多语言混合文本(中英文夹杂、特殊字符)

清洗包含中、英、日混合文本的客服对话,保留可见字符,去除控制字符(如制表符、换行符)和无效符号(如)。

def clean_multilingual(text: str) -> str:  
    # 匹配可见字符:中英文、日文(平假名、片假名、汉字)、数字、常用标点  
    pattern = r'[^\x00-\x7F\u4e00-\u9fa5\u3040-\u30ff\u30a0-\u30ff\uff00-\uffef]'  
    # \x00-\x7F 为ASCII控制字符,\uff00-\uffef 为全角符号范围  
    cleaned_text = re.sub(pattern, '', text)  
    # 额外处理日文假名与汉字的混合(无需额外处理,正则已包含范围)  
    return cleaned_text.strip()  

# 示例输入  
multilingual_text = "こんにちは!今天的天气→晴れです,温度25℃~"  
cleaned_multi = clean_multilingual(multilingual_text)  
print("清洗后:", cleaned_multi)  
清洗后: こんにちは今天的天气晴れです温度25℃  
  • 不同语言的Unicode范围需准确界定(如日文平假名\u3040-\u309F,片假名\u30A0-\u30FF)。

  • 避免使用宽泛的\w匹配,防止遗漏特定语言字符(如日文、韩文)。

总结

正则表达式是文本清洗的核心工具,其核心在于通过灵活组合基础语法(如字符匹配、量词限定、分组捕获等)设计精准的模式。从去除特殊字符、空白符到提取日志中的结构化信息,再到清洗 HTML 标签、社交媒体文本及多语言混合内容,正则表达式能高效处理各类文本噪声。实践中,需兼顾模式的鲁棒性以适应多样化输入,利用非贪婪匹配和精确分组优化性能,并通过拆分复杂模式或添加注释提升可读性。

THE END !

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值