复制粘贴带来的那些看得见的乱七八糟,两分钟就能收拾:多余的空格、多出来的空行、拖在后面的项目符号。看不见的那部分就不行了,而代价高的正是它。从一个网页或者一份文档里粘过来的文字,常常带着根本不显示的字符,它们会让一次搜索、一次比对、一次数据导入或者一个表单莫名其妙地失败,而谁也弄不明白为什么。
这件工具在清掉它们之前先把它们列出来,每一个都附上 Unicode 官方名称和码位。有两类值得认识。零宽字符:可以用它们在一段文字里藏进一个可辨认的图样,而这个图样能挺过复制粘贴。双向书写控制符:它们在不改动字节的情况下重排显示顺序,这就使得一段文字读起来跟它执行起来可以不是一回事。最后这种手法由剑桥的两位研究者在 2021 年以“Trojan Source”之名发表。
其余部分是些实实在在的方便:Unicode 组合规范化,Unicode 附件第 15 号和 W3C 都推荐所有内容采用这种形式;把不换行空格还原成普通空格;按您的要求把弯引号转成直的;以及把行末被断开的单词接回去,那是从 PDF 里复制文字时的一个坑。
怎么用
- 把您的文字粘进来。它不会离开您的设备。
- 看那张表:它会点出找到的每一个隐形字符、出现了多少次,以及它是干什么的。
- 选好要清掉哪些,然后把结果复制走。这些勾是实时生效的:每改一处,结果就重算一遍。
支持的格式
就是文字。如果您的剪贴板里还带着富文本格式,浏览器不会把它交给一个文本输入区:到这里来的本来就是纯文字,而这样正好。
一段文字,打进来或者粘进来
最多 200000 个符号。结果一键就能复制走。
它的限制
兼容性规范化是破坏性的,所以默认不勾
它会把连字“fi”拆成两个字母,把分数“½”变成“1/2”,把上标变成普通数字,把全角字符变成普通字符。有时这恰恰是比对之前想要的;有时这是信息的损失。定义它的那份 Unicode 附件明确提醒不要盲目套用,我们照这条提醒办。
关于变体选择符,我们把有文档的和只是观察到的分开说
Unicode 记载了它们的预期用途,那是给疑难显示情形留的一个例外机制,工具正是按这个理由把它们清掉。至于能拿它们藏任意数据,这确实是一种真实存在的手法,但我们只在 2025 年的一篇博客里见到过描述,而作者自己就说那是一种挪用。所以我们把它当成一项观察,而不是某个厂商确立的事实:这是本站的规矩。
Trojan Source 那次攻击的漏洞编号是有争议的
2021 年给这种双向重排手法分配了两个编号。这两个在公开数据库里都被标为“有争议”:Unicode 联盟不接受“这是我们规范的漏洞”这个说法,而它的理由并不荒唐,因为这些字符做的恰恰就是它们被设计来做的事。而那篇研究论文是真实的、可以核对的。这件事的两半我们都告诉您。
把行末断开的单词接回去,默认不勾
在从 PDF 里复制出来的文字上,这一项非常有用,那里的单词是被排版切断的。但它区分不了“被切断的词”和“正好落在行末的复合词”。所以工具只在两个小写字母之间接回去,这样就放过了 Paris-Brest 这样的写法和数字,并且把开关交给您。接完之后请务必再读一遍。
关于这个工具的问题
我的文字会被发到什么地方吗?
不会。三十秒就能验证:按 F12 打开开发者工具,切到“网络”标签页,清空列表,然后把文字粘进来。一行都不会冒出来。把网断掉再做一遍:工具表现完全一样,因为它用的那整份字符目录都写在页面里。
这些隐形字符到底是干什么用的?
大多数是正当用途。零宽连接符把一家人表情符号拼起来,书写方向标记让阿拉伯文和法文能混在同一句话里,软连字符标出一个词可以断开的位置。问题不在于它们存在,而在于它们跟着被复制的文字一起走、谁也看不见:于是搜索、比对或者导入就出错了,而人们要找上一个钟头。而在别人发来的文字上,它们还可以充当看不见的水印。
Trojan Source 是什么?
剑桥大学两位研究者 2021 年发表的一种手法。双向书写控制符在不改动一个字节的情况下重排一段文字的显示顺序:所以一段代码可以读起来是一回事、执行起来是另一回事,连项目的代码评审工具里也一样。为此分配了两个漏洞编号,两个在公开数据库里都被标为“有争议”,因为 Unicode 联盟不承认这是自己规范的漏洞。这件事的两半都是真的,我们两半都告诉您。
兼容性规范化那一项该勾吗?
只有在您知道为什么的时候才勾。在比对两段文字或者导入数据之前,它非常有用,因为它把视觉上的变体归并成同一个字符。但它是破坏性的:连字“fi”变成两个字母,二分之一那个分数变成三个符号,上标变成普通数字。定义它的那份 Unicode 附件提醒不要盲目套用。给人读的文字,就用默认勾上的那个简单的组合形式。
为什么我的弯引号默认不被转换?
因为对给人读的文字来说,它们才是对的引号。文字处理软件会自动替换成它们,而且它做得对:法语也好英语也好,讲究的排版用的就是它们。它们只在技术场合才成问题,比如一个数据文件或者一段代码,那里弯引号不算引号。所以这个勾是有的,但默认不打:您的文字要去哪个世界生活,得由您自己判断。