修剪 (Trim)
去除字符串前后空白的处理。大多数编程语言都提供标准方法。
修剪 (trim) 是去除字符串开头和末尾空白字符 (空格、制表符、换行符等) 的处理。几乎所有编程语言都将其作为标准方法提供,是用户输入验证、数据库保存前处理、文本比较预处理等各种场景中使用的基本字符串操作。
各语言的 trim 实现存在微妙的差异。JavaScript 除了 String.trim() 之外,还在 ES2019 中标准化了仅去除开头的 trimStart() 和仅去除末尾的 trimEnd()。Python 中 str.strip() 去除两端,lstrip() 去除开头,rstrip() 去除末尾。Java 11 在原有的 trim() 之外新增了 strip(),但这两者所针对的字符定义并不相同。trim() 的定义是去掉 "码点在 U+0020 以下的字符",因此全角空格 (U+3000) 和不间断空格 (U+00A0) 会被保留。strip() 遵循 Java 的空白判定,全角空格会被去除;但不间断空格作为非换行空格被排除在空白判定之外,所以在它这里同样会保留。这里需要注意的是,trim 与 strip 的这种对比只是 Java 内部的事情。JavaScript 的 trim() 和 Python 的 str.strip() 都会去除全角空格和不间断空格,若从方法名去推测行为就会读错。
在实际工作中 trim 特别重要的场合是表单输入的处理。用户在文本框中复制粘贴时,前后经常会混入不必要的空白。邮箱地址前后有空格会导致登录失败,搜索查询末尾有空格会改变搜索结果,忽略 trim 就会成为意想不到的故障来源。当要把值用作检索键或重复判定时,只去掉两端还不够,还需要把混入词与词之间的连续空白合并为一个的处理。另外,trim 终究只是统一写法的规范化,并不能代替转义和输入值的校验。若认为去掉了两端空白就变安全了,本该做的校验就会被漏掉。
常见的注意点是,把哪些字符视为空白因实现而异。零宽空格 (U+200B) 在 JavaScript 的 trim() 和 Python 的 str.strip() 中都会被保留。不具有宽度的字符往往被当作格式控制字符而不是空白来处理,一旦从复制来源的网页或 PDF 中混入,就会造成看上去是空栏却并非空字符串这样的判定偏差。BOM (U+FEFF) 更加麻烦,JavaScript 的 trim() 会去除它,而 Python 的 str.strip() 会保留,因此同一份输入用两者处理会得到互相矛盾的结果。并用 Unicode 规范化也是一种办法,NFKC 会把全角空格和不间断空格都映射为半角空格,所以先完成规范化再做 trim,可以减小语言差异带来的影响。不过零宽空格和 BOM 在 NFKC 下也不会变化,这些需要明确指定想去除的字符并单独处理。此外,日语的文章有时会用全角空格来做首行缩进,一律修剪两端就会让原本有意为之的缩进消失。
在与字符计数的关联上,是否进行 trim 会直接影响字符数。" 你好 " (前后有半角空格) 是 4 个字符,trim 之后变为 2 个字符。同一段文本会因 "含空格的数法" 与 "不含空格的数法" 而得到不同结果,因此在确认字符数限制时,基本原则是与施加限制的一方如何计算两端空白保持一致。若不清楚其规格,就按包含空格的、数值更大的那种数法来看,这样更不容易超出限制。