文本行排序去重
一行一条的清单:按中文拼音、长度或数字大小排序,顺带去掉重复行、空行和每行里重复的项。
排序
用 Intl.Collator 的 zh-CN 规则比较,汉字按拼音排,不是按 Unicode 码位
去重
当前不去重,只做其他变换。
其他变换
在上面粘贴多行文本
结果
使用说明
处理顺序固定,不能调:去掉每行首尾空白 → 去掉空行 → 行内去重 → 按分隔符拆分成多行 → 去重 → 排序 → 反转 → 加序号。之所以不让人自由排序这些步骤,是因为它们互不交换:先去重再排序,和先排序再去重,在「忽略大小写」这种判定下会给出不一样的保留结果;先加序号再去重还会出现断号。固定下来之后,同一份输入在任何时候处理结果都一样。
排序默认用 Intl.Collator('zh-CN'),中文按拼音排,这是它和普通字符串排序最大的区别。「按长度」那一档比较的是字符个数,中文一个字算一个字符,不区分全角半角;长短相同的行保持输入时的相对顺序,所以可以先用一个规则排一遍、再按长度排,做出「同类内容按长度排」的效果。三种排序都是稳定排序,比较函数对相同键值返回 0,不会把等键值的行打乱。
「按数值大小」只认整行都是数字的行,允许前置正负号和小数点,10 会排在 2 后面,-3 排在 1.5 前面。带单位、带前缀的行不算数字行,比如 10px、#10,它们按「非数字行」处理:选放末尾就集中到列表最后,选保持原位就留在原来的行号上,只把数字行之间重排。
去重的判定分三档:完全相同(空格和大小写都参与比较)、忽略首尾空格后相同、忽略大小写与首尾空格后相同。整行比较很容易被看不见的差异坑到——从表格或聊天记录复制来的手机号和邮箱经常带首尾空格,或者中间混了全角数字,看起来一样但字节不同,所以整理清单时建议直接用第三档,必要时配合「去掉每行首尾空白」。保留哪一处可选第一次或最后一次,保留最后一处时内部是从尾部往前扫的,但输出仍按原来的先后顺序排列,不会变成倒序。
行内去重针对的是一行里的多个项,比如 香蕉,苹果,香蕉,橙子 会变成 香蕉,苹果,橙子,按分隔符切分、保留第一次出现、忽略首尾空格。它和整行去重是两回事:行内去重删的是「项」,不影响行数;想知道删了多少可以看结果区那一栏。真要把一行里的多项拆成多行,用「按分隔符拆成多行」,填上逗号或顿号即可。
随机打乱用 crypto.getRandomValues 做 Fisher-Yates,取下标时用拒绝采样消除取模偏差,所以每一行的落位是均匀的,不依赖 Math.random。整个处理在浏览器本机完成,内容不上传,断网可用。常见的几种用法:整理从多个表格拼起来的手机号或邮箱清单(去重 + 忽略首尾空格);给密码本排个稳定顺序(字典序 + 加序号);把 CSV 某一列粘出来单独去重(去空行 + 去重);把歌单按名字长短重排(按长度)。要按词频看内容重点用词频统计;要生成 Markdown 表格用Markdown 表格生成;要在中英文之间批量补空格用中英混排空格;要抹掉手机号中间四位用数据脱敏。
常见问题
中文按拼音排序,为什么「阿」在「八」前面?
因为用的是 Intl.Collator 的 zh-CN 规则,按汉语拼音的字母顺序比较:a、ba、ca……所以「阿」排在「八」前面。如果拿默认的字符串比较(按 Unicode 码位),「阿」的码位 38463 远大于「八」的 20843,顺序会完全反过来。
按长度排序时,等长的行会不会被打乱?
不会。排序用的是稳定排序,比较函数对等长的行返回 0,它们之间的先后顺序保持和输入一致。所以先按某个规则排一遍,再按长度排,等长的行会保持上一个规则的结果,可以做出「先分组再按长度」的效果。
去重保留第一条还是最后一条有什么区别?
区别在于留下的是哪个位置的原文。保留第一条适合「清单按重要性排过序」的场景,前面的是想要的;保留最后一条适合日志、导出文件这类「后出现的才是最新状态」的场景。两种模式都不会改变被保留行之间的相对顺序。
手机号去重总也去不干净,是哪里有问题?
多半是空格和全角字符。从表格或聊天记录里复制的号码常带首尾空格、中间插入空格,或者用了全角数字,看起来一样但字节不同。先把去重模式切到「忽略首尾空格后相同」,再看行内去重能不能处理中间的空格;全角数字要先转成半角。
非数字行放末尾和保持原位,该选哪个?
要看用途。做「数字清单」时选放末尾,数字行会连续排在一起,一眼看完;做「按数值修正某一列」时选保持原位,非数字的那几行不会跑位。后者的实现是只对数字行之间重排,非数字行还待在原来的行号上,所以有时候会出现数字看起来没排整齐的错觉。
随机打乱为什么只改结果框,不改输入框?
为了让刷新前后一致。打乱依赖浏览器提供的随机数,如果直接改写输入框,预渲染出的内容和浏览器里的结果就会对不上。这里把打乱结果只放在结果框里,并记住当时输入和选项的指纹,一改选项这段打乱结果就自动作废,避免把过期的顺序复制出去。
处理顺序能不能自己调?
不能,顺序是固定的:去首尾空白、去空行、行内去重、按分隔符拆分、去重、排序、反转、加序号。因为这些操作互不交换,比如「先去重再排序」和「先排序再去重」在遇到忽略大小写时会给出不同结果,固定顺序是为了让结果可预期。
去重到底删了多少行,能对上吗?
结果区会分别给出输入行数、输出行数、删掉的重复行数、去掉的空行数和重复组数。用输入行数减去输出行数,应该正好等于重复行加上空行再加上行内去重删掉的项(行内去重删的是行内的项,不是行,所以不参与行数对账)。对不上就说明中间有按分隔符拆分,拆分只增行不删行。