文本到底是什么,以及工具为何意见不一
文本文件就是字节加上一种编码,而编码并不存储在文件里。只有约定俗成告诉程序某个字节代表“é”——这就是为什么同一个文件在一处能正常打开,在另一处却显示成“é”。UTF-8是现代的解决方案,常见的拉丁字母占1个字节,带重音的字母占2个字节,大部分中文、日文、阿拉伯文以及所有emoji占3到4个字节。UTF-16是Windows和JavaScript内部使用的编码,几乎所有字符都占2个字节,其余占4个字节。Windows-1252和Latin-1是旧系统至今仍在输出的单字节编码,也是乱码最常见的来源。关于这些页面,有一点值得了解:CSV查看器会检测您拖入文件的编码,包括UTF-16和Windows-1252,并允许您手动更改。普通文本框则不会——拖入的文件一律按UTF-8读取,所以Latin-1导出的文件中带重音的字母会显示错误,解决办法是先转换编码。
“字符”有四种含义,您需要哪一种,取决于是谁在设限。人眼看到的一个字符是一个字素簇。正则表达式匹配的是码位。JavaScript的string.length报告的是UTF-16单元数。数据库字段或HTTP头部衡量的是UTF-8字节数。对纯英文来说,四者结果一致,所以没人注意到——直到一个“家庭”emoji显示为1个字素、7个码位、11个UTF-16单元和25个字节,于是一条200个字符的消息被一个255字符的字段拒之门外。字符数统计正是为此同时显示全部四种数值。
看不见的字符也是真实存在的字符。不换行空格看起来和普通空格完全一样,却是完全不同的字符——从网页或文字处理软件复制的文本里经常带着它,它会破坏搜索、CSV解析以及按空格拆分的代码。零宽连接符是把多人emoji连在一起的东西。软连字符、方向标记和字节顺序标记都会随粘贴的文本一起过来。它们都不会显示在屏幕上,所以您得到的唯一信号就是计数与您看到的不一致——这正是字符计数器的一个实在用处。请注意,文本对比中的“忽略所有空白”选项会合并普通空格和制表符,但不会把不换行空格当作空格,因为它们本来就不是同一个字符。
换行符是差异对比有时把每一行都标为已修改的原因。Windows用回车加换行来结束一行,其他系统只用换行。在Windows编辑器里保存一个LF文件,其中每一行都会多出一个看不见的字节,于是按字节比较的工具——git diff、diff(1)——会报告整个文件都被重写了,把您真正做的那一处修改淹没其中。我们的文本对比和删除重复行在比较之前会按全部三种换行约定拆分行,所以一个仅仅是换行符变了的文件,在这里不会显示成一大片红色。这在阅读工具里是一种便利,在代码仓库里却是一个陷阱:请在源头用您的编辑器或git自带的换行符设置来修正它。
两个看起来完全相同的字符串可能比较结果不同,原因通常是规范化。Unicode可以用两种方式写出“é”:一个码位,或者一个普通的“e”后面跟一个组合用锐音符。它们显示效果相同,字节序列却不同,所以比较、去重或数据库查询都会把它们当作两个不同的值。macOS和Windows在文件名使用哪种形式上历来意见不一,这就是为什么从两台机器汇总的列表里,会出现看上去完全重复、却怎么也去不掉的条目。字符数统计可以帮您发现这种情况——两种形式的字素数相同,码位数却不同。这些工具都不会在两种形式之间转换;那是用带Unicode库的脚本一行就能完成的事,比如Python的unicodedata.normalize。
“字数”是一种判断,而不是一种测量。按空白拆分是英文的规则,把它套用到不在词与词之间加空格的中文、日文或泰文上,一篇长文章会被报告为一个词。我们的统计工具改用浏览器的Unicode分词功能,它知道每种文字里词从哪里开始。剩下的分歧在于连字符(“well-known”在这里和Word中算一个词,在某些工具里算两个)、单独的数字,以及怎样才算一个句子——“We met Dr. Smith”是一个句子,简单的拆分器却会算成两个。阅读时间则是在此之上的进一步估算:默读按每分钟238个词计算,这个数字来自一项荟萃分析,而不是博客之间互相抄来的那个整数。
浏览器确实不适合的情况
这个模块中的任何内容都不会被发送或存储,所以把未发表的草稿或专有源代码粘贴进来是安全的。这同时也设定了上限,我们宁可说清楚上限在哪里,也不愿您做到一半才发现。
大文件。整段文本都保存在标签页的内存中,并随着您的输入不断重新分析。几MB的内容很流畅;几百MB的日志文件就不行了,手机会比笔记本电脑更早撑不住。命令行没有这个问题,因为它是流式处理的:grep和ripgrep能搜索比内存还大的文件,sed和awk逐行转换文件,带去重参数的sort借助磁盘能对数千万行的列表去重。这些工具全都免费,macOS和Linux上都已预装。
差异很大的文档。文本对比在差异达到8000处时停止,因为超过这个数量,算法的内存开销会急剧增长到让标签页卡死,而且差异这么大的对比结果本来也没法看。同一文档的两个版本几乎不会达到这个上限;两份毫不相干的文档则会立刻达到。审查代码时,diff和git diff能处理任意大小的文件,而真正的三方合并工具能做到本页面完全做不到的事。
转换编码或规范化Unicode。这些页面只读取和报告,不在编码之间转换。iconv能在所有编码之间相互转换,file命令能猜出您手上是什么编码,Unicode规范化则只需一行Python,或者调用ICU的uconv。如果您要修复一份乱码导出文件,这就是该用的工具链。
任何重复性的工作。这些工具只在有人点击时才运行。统计四百份文档的字数,或者每次提交时压缩整个目录,都应该交给脚本或构建步骤——尤其是压缩代码,您的构建工具会做同样的压缩,还提供source map、监听模式和缓存,这些都是粘贴框给不了的。本页面适合处理您眼前的那一个文件。
现代CSS。CSS压缩会拒绝处理原生嵌套和现代媒体查询范围语法,而不是去压缩它们,因为它背后的压缩器比这两者都早,会悄悄删掉它不认识的内容。这是一种诚实的拒绝,而不是什么功能;解决办法是先用Sass、PostCSS或Lightning CSS把嵌套编译掉——您的构建工具几乎肯定已经在做这件事了。
名字相似的工具怎么选
字数统计与字符数统计。统计方式相同,突出显示的数字不同。字数统计首先显示字数、句数、段落数和阅读时间,这是衡量论文、文章或演讲稿的标准。字符数统计首先显示字符数、不含空格的字符数和UTF-8字节数,这是衡量网页描述、短信分段或数据库字段的标准。如果某个地方因为文本太长而拒绝了它,您需要的是字符数统计,尤其是其中的字节数。
文本对比与删除重复行。文本对比回答“这两个版本之间改了什么”,需要两段文本。删除重复行处理的是一个列表,回答“这里面有什么出现了不止一次”,它还能告诉您哪些条目重复了、重复了几次,能按自然顺序排序让item2排在item10之前,也能只保留恰好出现过一次的行。找出两个列表中只在其中一个出现的条目,是删除重复行的活儿,而不是文本对比的。
HTML压缩、CSS压缩与JavaScript压缩。三种语言,三款压缩工具,有一处重叠值得了解:HTML压缩也会压缩style块里的CSS和script块里的JavaScript,方式与另外两个页面相同。所以一个单独的HTML文件只需要一款工具,不需要三款。独立的.css和.js文件则需要用各自的页面。
XML查看器与XML格式化、XML校验。这里的查看器提供一棵可折叠的树让您浏览,适合文档很大、您要从中找东西的时候。开发者工具中的格式化和校验工具,给您的是可以粘贴回文件的缩进文本,以及出错位置的准确行号和列号。一个用于阅读,另一个用于编辑和修复。
CSV查看器与用Excel打开文件。这不是两个工具之间的比较,但却是人们实际在做的比较。Excel在打开文件时就会自动转换,而且不会征求您的意见:产品编码00123变成123,零件号5-3变成3月5日,长订单号变成科学计数法,而德国系统导出的分号分隔文件则全部挤进A列。查看器把每个值都按原样作为文本显示,让您看到别人实际发给您的是什么。
Markdown预览与Markdown转PDF。预览工具用于在输入的同时实时检查README是否会按GitHub的方式渲染。文档工具中的Markdown转PDF则用于生成带分页的成品文档。在这里检查,在那里发布。