本文来源公众号“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'<.*?>'
# 额外处理特殊转义字符(如 、&)
text = re.sub(r' ', ' ', text)
text = re.sub(r'&', '&', text)
cleaned_text = re.sub(pattern, '', text).strip()
return cleaned_text
# 示例HTML文本
html = "<div class='content'><p>这是一段包含 HTML标签的文本&特殊符号。</p></div>"
cleaned_html = clean_html_tags(html)
print("清洗后:", cleaned_html)
清洗后: 这是一段包含 HTML标签的文本&特殊符号。
-
<.*?>
匹配以<
开头、>
结尾的任意内容,?
表示非贪婪匹配(尽可能少匹配字符,避免跨越多标签)。 -
先处理
(空格实体)和&
(&符号转义),再统一去除标签,确保文本可读性。
复杂场景清洗策略
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 !
文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。