删除重复行

四种行级判等口径可选:严格全等、去首尾空白、忽略大小写、再清零宽字符;Set 哈希保留首次出现位置,重复行统计可导出。

输入 11 行,保留 7 行,删除 4 行(第 4、5、9、10 行)。切换口径会得到不同答案:去首尾空白口径下第 7 行与第 3 行判等,共删 5 行。

重复统计表(默认口径「严格全等」下的演示数据;换口径后自动刷新,超过 12 行用「加载更多」展开)
行内容(判等键)出现次数首次出现行号
import pandas as pd21
df = pd.read_csv("data.csv")22
df.head()33
不可见字符对照表(trim 的真实边界,按 ECMA-262 WhiteSpace 产生式逐字符实测)
码点字符trim() 是否清除Unicode 类别
U+0009水平制表符 Tab是WhiteSpace/Zs
U+000B垂直制表符 VT是WhiteSpace/Zs
U+000C换页符 FF是WhiteSpace/Zs
U+0020半角空格 SP是WhiteSpace/Zs
U+00A0不换行空格 NBSP是WhiteSpace/Zs
U+2003EM SPACE 空格是WhiteSpace/Zs
U+3000表意空格(中文全角)是WhiteSpace/Zs
U+FEFF零宽不换行空格(BOM)是WhiteSpace/Zs
U+200B零宽空格 ZWSP否Cf(格式字符)
U+200D零宽连接符 ZWJ否Cf(格式字符)
U+200E从左至右标记 LRM否Cf(格式字符)
U+2060文字连接符 WJ否Cf(格式字符)

使用方法

  1. 把文本粘进输入框。默认示例是一段含重复的 11 行代码:同一行出现 2~3 次,还混着空行、带首尾空格的行和全大写变体。
  2. 选判等口径。不确定就先用「严格全等」——它只删逐字节相同的行,最安全。
  3. 点「删除重复行」或按 Ctrl+Enter(Mac 上 Cmd+Enter;Enter 本身留给换行)。
  4. 输出区给出保留结果,统计条报出「输入几行、保留几行、删了第几行」;重复次数超过 1 的行可在重复统计里核对。
  5. 「复制结果」带走输出;「导出重复统计 CSV」下载每个重复行的出现次数与首次出现行号(带 BOM,Excel 不乱码);「载入示例」随时还原演示数据。

这个删除重复行工具能解决什么

日志去重是最典型的场景:同一个异常栈一晚上刷几千次,删重后只剩每种一条,但行尾的不可见字符会让肉眼相同的两行被判成不同——比如从 Windows 日志粘来的行尾带回车符、从 Excel 粘来的行首带 BOM。本页的四种口径就是为了让你显式选择「什么算同一行」。

代码清单去重是第二类:import 语句重复、依赖列表里同一包写了两次。此时「忽略大小写」口径要慎用——Python 的 import pandas 与 IMPORT PANDAS 在严格口径下是两行,判等后合并可能改变语义。

词表、邮箱列表、优惠券码清洗是第三类:先删重复行再交给后续流程,重复统计表能告诉你哪个值重复了多少次、第一次出现在哪一行,方便回溯上游为什么重复写入。

本页不做的事:不删空行(那会改变语义,需要时用删除空行);不合并相邻重复段;不做模糊近似判等——「看起来差不多」的两行永远按不同行处理。

原理与规则说明

删除重复行的判等核心是 Set.prototype.has/add:遍历每一行,先算「判等键」(按所选口径规范化),键没见过就保留并记录,见过就跳过。Set 迭代按插入序,天然保留首次出现位置,不需要额外的序号数组。这是 O(n) 哈希判等;用 indexOf 在结果数组里找重复则是 O(n²)——本机实测 5000 行全部唯一时 indexOf 要 22.46 ms 而 Set 只要 0.42 ms(54 倍),2 万行差 173 倍,5 万行差 614 倍(9.1 秒对 15 毫秒),10 万行起 indexOf 已经不可用。

切行必须写 split(/\r?\n/)。写成 split('\n') 时 CRLF 文件的每行尾部会留一个 \r,「b\r」与「b」判不等,重复删不掉;单独的 \r(旧 Mac 换行)也会把两行粘成一行。末尾换行还有第二坑:'a\n'.split('\n') 得到 ['a', ''],多出一个空串。本页的处理是——原文以换行结尾就 pop 掉这最后一个空串,不以换行结尾就保留;空行本身是真实内容,不算换行符的产物。

四种口径的规范化函数依次是:原样(严格全等);trim()(ECMA-262 的 WhiteSpace 产生式,会顺手清掉 U+00A0、U+FEFF 和各类 Zs 空格);再加 toLowerCase();再加 /[\u200B-\u200D\u2060]/g 清零宽格式字符。注意 trim 清不掉 U+200B/200D/2060——它们是 Cf 类格式字符,不在 WhiteSpace 清单里,所以第四个口径才存在。

BOM 的危害不在「整表都带 BOM」(那种情况判等口径一致,反而正常),而在只有部分行带 BOM:表头手写、数据行从 Excel 粘贴时,「id」与「\uFEFFid」逐字节不同,严格口径下 4 行输入会判出 4 个唯一值,重复完全没被识别;切到去首尾空白口径,trim 把 U+FEFF 一并清掉,立刻回到 2 个。

完整示例(数值仅作演示)

删除重复行的默认示例是 11 行文本,严格全等口径:保留 7 行、删除 4 行,删的是第 4、5、9、10 行。逐行看——第 1 行 import pandas as pd 保留,第 4 行与它逐字节相同被删;第 3 行 df.head() 保留,第 5、10 行被删;第 6 行空串也是一行,第 2 次出现才删,这里只出现一次所以保留;第 7 行「 df.head() 」带首尾空格,严格口径下是第 2 个唯一值,第 8 行 IMPORT PANDAS AS PD 大小写不同照样保留。

同一份输入切换口径:去首尾空白保留 6 行(第 7 行的键变成 df.head(),撞上第 3 行);再去大小写保留 5 行(第 8 行也撞上第 1 行);再清零宽字符仍是 5 行——演示数据里没有零宽字符,口径 2 与 3 在这份输入上答案相同,这正是「口径要对数据敏感」的直观演示。

另一个七行样本可以拉开四档口径的差距:df.head()、带 BOM 的同名行、NBSP 开头的行、两侧空格的行、尾部带零宽空格的行、单字符 A、再来一行 df.head()。严格口径 6 个唯一,trim 口径 3 个,加忽略大小写仍 3 个,再清零宽只剩 2 个。

输入范围与对照表

判等口径规范化函数默认示例结果典型场景
严格全等原样(键 = 行本身)保留 7 行 / 删 4 行代码、配置,字节级一致才算重复
去首尾空白trim()保留 6 行 / 删 5 行手工录入、Excel 粘贴(顺带清 BOM)
忽略大小写trim().toLowerCase()保留 5 行 / 删 6 行邮箱、域名、URL 清单
清零宽字符trim + 清 U+200B/200D/2060 再忽略大小写保留 5 行 / 删 6 行从网页、PDF 反复复制粘贴的文本

不可见字符对照表见工具区:前 8 行会被 trim 清除(WhiteSpace 或 Zs 类),后 4 行不会被任何口径自动清除,除非选「再清零宽字符」。

输入范围、边界与精度说明

规模上限 20 万行:Set 构建 20 万个字符串键实测 108.9 ms,文本约 2.3 MB,加上 Set 结构的额外内存,普通设备无压力;超过后本页不做截断,但浏览器标签页内存吃紧时可能卡顿,建议分段处理。空输入是合法输入:0 行进、0 行出、删除 0 行,不报错。

边界行为逐条定义过:全部行相同时唯一 1 行、删除 n−1 行;单行无换行时原样返回、不补换行符;输入只有一个空行时输出为空文本——这是正确结果(那一个空行被保留了),不是故障。行内容永远按字符串处理,不做数字类型转换,文本世界里不存在「1 与 1.0 相等」。

常见误用的正确解释:第一,删完比预期多一行,多半是末尾换行产生的空串被当成了一行——本页已按「原文是否以换行结尾」处理,其他工具未必;第二,strict 口径删不掉 CRLF 文件的重复,是 \r 留在行尾,先选去首尾空白口径即可;第三,去重不等于排序,首次出现顺序就是输出顺序,需要字典序请用按字母排序行。

常见问题

删重复行之后顺序乱了吗?

没有。Set 按插入序迭代,输出顺序 = 每个值首次出现的顺序。要与原文件「先排序再去重」的结果一致,先过打乱行工具反而会破坏这个性质,注意区分。

为什么两个看起来一模一样的行删不掉?

多半是行里藏着不可见字符:行尾 \r(CRLF 文件)、行首 BOM、零宽空格。对照表里逐个列了码点;先切「去首尾空白」口径,仍不行再切「再清零宽字符」。

空行会被删掉吗?

只有空行出现两次及以上时才删多余的那个——空串也是一个合法的行值。想把空行全部清掉是另一个需求,交给删除空行工具。

20 万行以上会怎样?

本页不设硬拒绝,但 Set 构建实测 20 万行 108.9 ms,几十万行级别内存与耗时线性上涨,建议先按 20 万行拆分。五万行量级用 indexOf 写法要 5 秒以上,本页不用那种实现。

忽略大小写对中文有意义吗?

没有。toLowerCase 只影响拉丁字母与部分扩展字符,中文行在口径 2 与口径 1 下结果相同;对中英混排的清单,它只合并英文部分的差异。

重复统计里的「首次出现行号」从几开始数?

从 1 开始,与编辑器状态栏一致。行号按切行后的顺序计,末尾换行不产生额外行号。

CSV 为什么带 BOM,而输出文本不带?

Excel 依赖 BOM 识别 UTF-8,不带会乱码;但 BOM 粘进文本文件会变成行首 U+FEFF,正好制造本页要清除的那种幽灵差异,所以只给 CSV 加。

输入会传到服务器吗?

不会。判等只用 Set 与字符串方法,全程在浏览器本地执行,Network 面板可见零请求;刷新页面输入即消失。

相关工具

更多文本处理工具见分类页。