PHP 中 trim 函数对多字节字符的使用和限制

先来判断下这段代码的输出是否一致?

$string = '沈唁 ';
var_dump(trim($string));
var_dump(preg_replace('/^[\s\0]+|[\s\0]+$/u', '', $string));

如果你觉得是一致的,那么就是大错特错了。

在日常工作中,经常需要处理字符串。其中一种常用的情况是,需要删除字符串两端的空白字符,这就是 trim() 函数原本的作用。

但是标准的 trim() 函数不能处理多字节字符。

什么是trim()函数?

#PHP#中, trim() 函数用于删除字符串的开头和结尾的空白字符。默认情况下,这些字符包括:

  • "\0" - NULL
  • "\t" - 制表符
  • "\n" - 换行
  • "\v" - 垂直制表符
  • "\r" - 回车
  • " " - 空格

mbstring 扩展

在很多语言中,每个必要字符都能一对一映射到 8 bit 的值,但也有一些语言需要非常多的字符来书面通讯,以至于它们的编码范围不能仅仅包含在一个字节里。

开发多字节字符编码方案是为了在基于字节的常规编码系统中表达超过 256 个字符。

在使用trimsplitsplice 等等操作多字节编码的字符串的时候,特别需要注意,由于在这种编码方案下,两个或多个连续字节可能只表达了一个字符,所以需要使用专门的函数。 否则,你可能会得到一个以乱码的字符串结尾。

mbstring 提供了针对多字节字符串的函数,能够帮开发者处理 PHP 中的多字节编码。

mbstring 扩展的使用和普通字符串操作函数一致,而且仅仅需要加上mb_前缀即可。

类似于:

  • split => mb_split
  • strlen => mb_strlen
  • substr => mb_substr

以此类推,trim 是不是可以直接改为调用mb_trim

答案是也不是。因为你可能会得到一个错误:

PHP Fatal error:  Uncaught Error: Call to undefined function mb_trim()

mb_trimmb_ltrimmb_rtrim

从 2022 年 8 月份就有人在 php-src 的 issue 进行了反馈,这三个函数也是前不久刚刚通过 RFC,合并到 PHP 内核中新增的。

https://github.com/php/php-src/commit/a80b6d7b99ae885cb450a563a788f57917cef74e

function mb_trim(string $string, string $characters = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"): string

function mb_ltrim(string $string, string $characters = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}", ?string $encoding = null): string

function mb_rtrim(string $string, string $characters = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}", ?string $encoding = null): string

所以虽然 8.3 刚发布,但是 8.3 中确实没有这三个函数,可能需要在 8.3.1 中才能使用了。

不过 PHP 足够灵活,使我们能够根据需要创建自定义的函数,如多字节 mb_trim() 函数。

if (!function_exists('mb_trim')) {
    function mb_trim($string)
    {
        return preg_replace('/^[\s\0]+|[\s\0]+$/u', '', $string);
    }
}

2 条评论

发表评论

*