3、PHP 8.4 新特性 - grapheme_str_split 函数

作者: 温新

图书: 【PHP 8.4 新特性】

阅读: 143

时间: 2025-01-18 11:41:23

PHP 8.4 引入了 grapheme_str_split 函数,它主要用于按 可视字符(graphemes) 来分割字符串,而不是传统的字符。这个新函数的引入解决了在处理 Unicode 字符时的一个常见问题,即 Unicode 字符可能由多个字节组成,而普通的 str_split()mb_str_split() 无法正确处理这种情况。

背景

在字符串处理中,有时我们需要分割字符,而不是字节。例如,Emoji 或带重音符的字符(如 é)可能会由多个字节表示,但我们通常认为它们是一个字符。grapheme_str_split 可以按照可视字符来拆分字符串,不管它们由多少个字节组成。

函数签名

grapheme_str_split 函数与 mb_str_split 函数相似,支持指定一个整数参数 $length 来确定每个分块的长度。如果指定的长度大于整个字符串或某部分图符的长度,那么整个字符串或该部分将会被返回。

当传递一个空字符串时,grapheme_str_split 函数会返回一个空数组。

这个特性使得开发者可以根据需要灵活地分割字符串,特别是对于包含复杂脚本或表情符号的字符串,能够确保每个分块保持其图形单位的完整性,避免因为不当的分割而导致字符显示异常。

/**
 * 将字符串拆分为图符的数组或图符块的数组。
 *
 * @param string $string 要拆分为单个图符或图符块的字符串。
 * @param int $length 如果指定了此参数,返回数组中的每个元素将由多个图符组成,而不是单个图符。
 *
 * @return array|false 返回图符或图符块的数组,失败时返回 false。
 */
function grapheme_str_split(string $string, int $length = 1): array|false {}

grapheme_str_split 用法

案例一:基本用法

<?php

$string = 'hello 🌍';
$result = grapheme_str_split($string);
print_r($result);

输出

Array
(
    [0] => h
    [1] => e
    [2] => l
    [3] => l
    [4] => o
    [5] =>  
    [6] => 🌍
)

在这个例子中,字符串 "hello 🌍" 被正确分割成可视字符,每个字符作为数组的一个元素。注意 🌍 这个 Emoji 被作为一个单独的字符处理。

案例二:按长度分割

<?php
    
$string = "hello 🌍";
$result = grapheme_str_split($string, 2);
print_r($result);

输出

Array
(
    [0] => he
    [1] => ll
    [2] => o 
    [3] =>  🌍
)

案例三:对比 mb_str_split

<?php

$string = 'é අයේෂ්';
$mbResult = mb_str_split($string);
print_r($mbResult);

$graphemeResult = grapheme_str_split($string);
print_r($graphemeResult);

输出

Array
(
    [0] => é
    [1] =>  
    [2] => අ
    [3] => ය
    [4] => ේ
    [5] => ෂ
    [6] => ්
)
Array
(
    [0] => é
    [1] =>  
    [2] => අ
    [3] => යේ
    [4] => ෂ්
)

为什么需要 grapheme_str_split

在处理 Unicode 字符串时,单个字符(尤其是 Emoji 或带有组合字符的字符)可能由多个字节组成。传统的 str_split()mb_str_split() 无法正确处理这种情况,因为它们依赖于字符的字节数进行分割,而不是字符本身的视觉单位(graphemes)。

例如,字符 é 是一个可视字符,但它可能由两个字节组成。grapheme_str_split 会正确地将其当作一个单独的字符,而不是分割成两个字节。

向后兼容性影响

新的 grapheme_str_split 函数是在 Intl 扩展中新引入的,并且声明在全局命名空间中。除非已经存在一个同名的函数,否则这一变更不应该引入任何向后兼容性问题。

请登录后再评论