空白字符

空格、制表符、换行符等不可见字符。在文本处理和布局中发挥重要作用。

空白字符 (whitespace) 是指在屏幕上不以可见形式显示的字符的统称。包括半角空格 (U+0020)、制表符 (U+0009)、换行符 (LF: U+000A, CR: U+000D)、全角空格 (U+3000) 等。空白字符在文本格式化、代码缩进、数据分隔等所有文本处理中都发挥着重要作用。

Unicode 定义了多种多样的空白字符。除了常见的半角空格外,不间断空格 (U+00A0) 用于防止换行,对应 HTML 的  。全角空格 (U+3000) 在日语排版中用于段落缩进。零宽空格 (U+200B) 显示宽度为零,用来为长串英文数字等提供折行位置的提示。不过它在 Unicode 的分类上并不属于空白字符 (具有 White_Space 属性的字符),而是格式控制字符,在后文所述的正则表达式空白类中不被当作空白处理。此外还有 em 空格 (U+2003)、en 空格 (U+2002)、窄空格 (U+2009) 等众多排版用途的空白字符。

CSS 的 white-space 属性控制 HTML 中空白字符的显示方式。normal 将连续空白折叠为一个并自动换行。pre 保留源代码中的空白。nowrap 抑制换行。pre-wrap 保留空白同时允许自动换行,适合代码块的显示。如果只想保留换行而把连续空格折叠掉,可以使用 pre-line。另外在 CSS Text Module Level 4 中,white-space 被重新定义为同时指定 white-space-collapse 与 text-wrap-mode 的简写属性,normal 相当于 collapse wrap,pre 相当于 preserve nowrap。原有的 4 个关键字仍然可用,因此并不必须改写;但如果只想单独控制折行行为,也可以直接使用 text-wrap-mode 这类单项属性。

编程中空白字符的处理因语言而有很大差异。Python 使用空白 (空格或制表符) 进行缩进,缩进不一致会导致语法错误。YAML 的缩进不能使用制表符,只能用空格书写 (制表符若作为值的内容则可以写)。JSON 中空白仅用于提高格式的可读性,通过 minify (去除空白) 可以减小体积。不过削减幅度需要连传输方式一起考察。带缩进时为 1,799 字节的 JSON 经 minify 后变为 1,007 字节,但在施加 gzip 压缩的状态下则为 191 字节与 161 字节,差异几乎不再留存 (以 Python 3 实测)。空白容易被压缩掉,因此在以 gzip 传输为前提的 API 中,不要过高估计 minify 的效果,才更符合实际。

正则表达式的 \s 匹配空白字符,但作为对象的字符范围因语言和引擎而异。零宽空格 (U+200B) 在 JavaScript 和 Python 中都不匹配 \s。另一方面,与 BOM 相同的字符 (U+FEFF) 在 JavaScript 中匹配 \s,但在 Python 的 re 中不匹配 (以 Node.js 26 / Python 3 实测)。不间断空格 (U+00A0) 与全角空格 (U+3000) 在两种语言中都匹配。也就是说,"明明去除了空白却还留着"这一现象,多数情况下只是该字符没有进入引擎的空白定义而已。字符消不掉时,不要依赖 \s,请明确指定想要去除的码点。

常见的注意事项是外观无法区分的空白字符混用。半角空格和全角空格、普通空格和不间断空格看起来相同,但程序将它们视为不同的字符。复制粘贴时混入意外的空白字符导致字符串比较失败、CSV 解析出错等问题在实际工作中经常发生。

在与字符计数的关联上,是否将空白字符计入字符数是一个重要的判断点。一般的字符计数包含空白,但要求"不含空白的字符数"的场景也很多。是否计入空白会随媒体和委托方的规定而变化,因此在稿件的委托与承接中,与字数的约定一起确认下来最为稳妥。另一方面,社交媒体的发帖上限会把空白也算作 1 个字符。实务中先掌握"含空白"与"不含空白"两个数值,并事先弄清提交方采用哪一种基准再做调整,就能避免返工重写。混入全角空格或连续空格时,排除后的数值会与预想产生偏差,所以在计数前把多余的空白整理干净会更好。

分享这篇文章