应删除连续重复出现的标点符号,如将"???"变为"?",而非全局去重;常用正则re.sub(r'(1)\1+', r'\1', text)实现,兼顾空格清理时可追加\s+替换。\w\s ↩

移除字符串中“所有重复的标点”,关键要先明确:是指删除**连续重复出现的标点符号**(比如 ??、!!!、... ),还是指让**整个字符串里每种标点只保留一次**(比如把所有逗号、句号、问号各留一个)?从常见文本清洗场景看,绝大多数需求是前者——即压缩连续重复的标点为单个,避免噪音干扰分词或模型输入。
压缩连续重复的标点(最常用)
这是处理用户输入、社交媒体文本、OCR识别结果时的典型操作。例如将 "Wow!!! This is great???..." 变成 "Wow! This is great?..."。
- 用正则表达式最简洁:匹配两个及以上相同标点,替换成一个
- 代码示例:
import re def collapse_consecutive_punctuation(text): # 先匹配所有 ASCII 标点(含 . , ! ? ; : 等),支持连续2次及以上 return re.sub(r'([^\w\s])\1+', r'\1', text) - 如果只想处理特定标点(如只压缩多个句点),可写成:
re.sub(r'\.{2,}', '.', text);对问号同理:re.sub(r'\?{2,}', '?', text) - 注意:
[^\w\s]匹配所有非字母、数字、下划线、空白的字符,基本覆盖常见标点;若需更精准(比如排除引号或括号),可显式列出:[.!?;:,]
全局去重:每种标点在整个字符串中只出现一次
这种需求较少见,通常用于特殊格式生成或调试,比如想确保整段文字最多含一个感叹号、一个问号。
- 思路:遍历字符串,记录已见过的标点类型,跳过后续重复出现的同类标点
- 代码示例:
import string <p>def keep_first_occurrence_of_punctuation(text): seen = set() result = [] for char in text: if char in string.punctuation: if char not in seen: result.append(char) seen.add(char) else: result.append(char) return ''.join(result)
- 该方法保留首次出现的每个标点,其余同类型标点全部丢弃;字母、数字、空格等不受影响
先清理再压缩:兼顾标点和空格规范
实际应用中,连续标点常伴随多余空格(如 hello!!! ???)。可一并优化:
- 组合操作:先压缩重复标点,再合并多余空格
- 示例:
import re def clean_punct_and_spaces(text): # 压缩连续标点 text = re.sub(r'([^\w\s])\1+', r'\1', text) # 合并多个空格为单个,并去掉首尾空格 text = re.sub(r'\s+', ' ', text).strip() return text - 这样输出更干净,适合送入 NLP 工具链
不复杂但容易忽略的是标点边界——比如 word!!! 中的三个叹号是连续的,应压缩;而 word! another? 中的 ! 和 ? 是不同符号,不视为“重复”,各自保留。

















