文本去重排序(按行去重 · 忽略大小写 · 自然排序)
粘进一列文本,按行去重、去掉空行、清理首尾空白,再按字典序、自然序(item2 在 item10 前)或字符数排序,并告诉你哪些行被合并了。处理在浏览器本地完成。
A · 清洗与去重
B · 排序
什么算同一行,怎么排
去重、排序里最容易做错的几件事
日常里最烦的文本整理就那几件:从 Excel 里复制一列出来发现一半是重复的,接口文档的字段列表里有 user_id 和 User_ID,日志里几千行 ERROR 只想留一份看看有几种,item2 / item10 / item20 排序以后按字典序变成了 item10、item2、item20。
这些活共同点是「说得出规则,手做必然做错」,所以工具把它拆成两段可以随便组合的规则:A 段清洗去重(去空白、丢空行、忽略大小写、留第一条还是最后一条),B 段排序(字典序 / 自然序 / 按长度 / 倒序)。四格统计告诉你行数是怎么变少的,下面那行「被合并的重复行」直接列出哪些内容被合并了、各自出现几次、分别在第几行——去重最怕的是悄悄少了几行又不知道少了什么。
什么算「同一行」
去重比较的是清洗之后的整行文本,逐字符比,不做任何归一化。所以:
- 勾了「去掉每行首尾空白」,
apple和apple是同一条;没勾就是两条。 - 勾了「忽略大小写」,比较用的是转小写之后的整行,
Apple、apple、APPLE归成一条,保留下来的那条内容取决于「保留第一条还是最后一条」。 - 中间的空格永远算内容:
new york和new york(两个空格)是两条,全角空格和普通空格也是两条。 - 行内的换行写法不影响判断:
\r\n、\n、以及单独的\r(很老的 Mac 文件)都算换行,输入里用哪种都行,输出统一用\n。 - 输入结尾的那个换行不会被算成"多出来的一行空行"。
大小写转换用的是通用的 Unicode 映射,toLowerCase 不认识语言,所以德语 ß 和 SS 不会被算成同一条(本来也不该),而土耳其语的 İ 转小写会多出一个组合符。「忽略大小写」对中文、数字没有任何作用,中文没有大小写形态。
排序的三种口径
「排序后输出」是总开关,不勾就只是去重,剩下的行保持原来的先后。勾了以后:
- 默认(字典序):按字符的 Unicode 编码单元从小到大比。这条口径很"生硬"但可预测:空格和标点排在字母前面(
- a在aa前),大写字母全部排在小写字母前面(Zoo在apple前,因为Z是 90、a是 97),中文字符按自己的码点排,不是拼音顺序。要拼音或带重音的正确顺序,请用系统里的排序功能,这里不猜。 - 自然排序:把行里的连续数字段当成一个整体来比大小,所以
item2在item10前面,第3章在第10章前面。数字再长也不怕——比较用的是「先去前导零、再比长度、最后逐字符」,从不转成Number,所以编号99999999999999999999不会被四舍五入成同一个值。前导零多的那段排在前面(item007在item7前)。只有 ASCII 的0-9会被当数字,全角3和普通字符一样处理。 - 按字符数排序:先比行长,短的在前;长度相同的再按上面两种口径比。数字段在这里不特殊,
item10(7 个字符)就比item2(5 个字符)长。
「倒序」作用在最后那一条比较规则上,每一步比较都反过来,效果就是把排好的列表整个翻转;去重以后不会有两条完全相同的行,所以不存在"翻转以后同长度行的先后变了"这种边角情况。没勾「排序后输出」时,「倒序」单独生效,就是把去重后的列表整个翻转一次(日志这类"越后面越新"的列表常用)。
处理顺序
规则之间有先后,结果才算得确定:
- 按换行拆开(先拆,再谈别的)。
- 每行去掉首尾空白(如果勾了)。
- 丢掉空行(如果勾了)——空是指第 2 步之后什么都没有。所以没勾去空白时,一行只有几个空格不算空行,会被留下。
- 分组合并(比较键:整行,或忽略大小写时的小写形式),留第一条或最后一条。
- 排序(如果勾了)。
- 用
\n拼起来放进结果框。
什么时候结果不能直接用
- 需要"语义去重"的时候:
1,000和1000、张三和张三(中间全角空格)、Ⅲ和III,这里都是不同的行。想按含义合并得自己先归一化。 - 保留哪一条是有讲究的:默认留第一条。如果你的列表是「越后面越新」的日志或者带版本号的记录,要的往往是最后一条,记得勾上;勾了以后那一行仍然在它原来所在的位置上,不会被挪到列表末尾。
- 中文排序:码点顺序 ≈ 常用字偏靠后、生僻字靠前,和拼音、部首、笔画都无关,中文列表勾这个排序基本没意义,只当"按 Unicode 分组"用。
- 超大列表:上限 40000 字符(大约几千行短文本)。超出就只处理前 40000 个字符,末尾那一行可能是半截,提示里会写出来。真要处理几十万行请用命令行工具,浏览器里那样做只会卡住。
- 结果框是纯文本:复制出去就是一行一条。如果你的目标是「去重后仍然保持原来的列结构」(比如三列制表符),只要每行整块复制别手动改,这里不会重排行内内容。
常见问题
Q:为什么我的列表看起来顺序"对",但重复没被去掉?
九成是首尾空白或者大小写在作怪:apple 和 apple 在默认(勾了去空白)下会合并,但如果那行末尾是不可见字符(零宽空格 U+200B、从网页复制带来的 \u200E 方向标记),trim 不认识它们,就不会合并。看「被合并的重复行」那一行:如果你明明看到两条一样的内容却没被列出来,就是这个原因。
Q:空行为什么算进输入行数? 「输入行数」数的是拆出来的行,不是内容;「去掉的空行」单独一格告诉你其中几行是空的被丢了。不勾「丢弃空行」时那一格显示「—」,意思是"不适用"。
Q:能不能让中文按拼音排?
不能。按拼音排序要带一张几千条的多音字表,还得决定 重庆 读 chóngqìng 还是 zhòngqìng——这是字典级别的工作,塞进一个浏览器小工具只会让结果更难预测。
Q:粘贴的内容会上传吗?
拆行、比较、排序都是脚本里的循环,没有 eval;你粘进来的文本不进请求体,不会离开这台设备。