将一个多字节字符串转换成字符数组

4
假设在2019年,任何不支持UNICODE的解决方案都是错误的。在PHP中将字符串转换为UNICODE字符数组的最佳方法是什么?
显然,这意味着使用括号语法访问字节以及使用str_split都是错误的:
$arr = str_split($text);

对于像这样的示例输入:

$string = '先éé€‍ ‍❤️‍';

我期望:

array(16) {


[0]=>
  string(3) "先"
  [1]=>
  string(2) "é"
  [2]=>
  string(1) "e"
  [3]=>
  string(2) "́"
  [4]=>
  string(3) "€"
  [5]=>
  string(4) ""
  [6]=>
  string(4) ""
  [7]=>
  string(4) ""
  [8]=>
  string(3) "‍"
  [9]=>
  string(1) " "
  [10]=>
  string(4) ""
  [11]=>
  string(3) "‍"
  [12]=>
  string(3) "❤"
  [13]=>
  string(3) "️"
  [14]=>
  string(3) "‍"
  [15]=>
  string(4) ""
}

你想用什么编码方式进行编码?utf8吗? - Danyal Sandeelo
@DanyalSandeelo 不管使用哪种编码方式,我只想获取代码点的数组,而不是代码单元、字形簇或字节。 - Dharman
2个回答

4

如果想要使用PREG_SPLIT_NO_EMPTY标志来传递空模式,请注意。否则,您可以编写一个带有\X(Unicode点)和\K(重新启动全字符串匹配)的模式。为了完整起见,我将包括mb_split()调用和preg_match_all()调用。

代码: (演示)

$string='先秦兩漢';
var_export(preg_split('~~u', $string, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_split('~\X\K~u', $string, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_split('~\X\K(?!$)~u', $string));
echo "\n---\n";
var_export(mb_split('\X\K(?!$)', $string));
echo "\n---\n";
var_export(preg_match_all('~\X~u', $string, $out) ? $out[0] : []);

所有产品:
array (
  0 => '先',
  1 => '秦',
  2 => '兩',
  3 => '漢',
)

来自 https://www.regular-expressions.info/unicode.html:

如何匹配单个 Unicode 字形

在 Perl、PCRE、PHP、Boost、Ruby 2.0、Java 9 和 Just Great Software 应用程序中,无论是将单个码点编码还是使用组合标记将其编码为多个码点,都可以轻松地匹配单个字形:只需使用 \X。

你可以将 \X 视为点的 Unicode 版本。不过,有一个区别:\X 总是匹配换行符,而点除非启用了点匹配新行匹配模式,否则不会匹配换行符。


更新,DHarman 已提醒 PHP7.4 中现在可用 mb_str_split()

新函数的默认长度参数为 1,因此对于该情况可以省略长度参数。

https://wiki.php.net/rfc/mb_str_split

Dharman 的演示:https://3v4l.org/M85Fi/rfc#output


这是否意味着PHP本地没有多字节版本的str_split可用,除了正则表达式匹配之外?我想对于大型应用程序来说,正则表达式匹配会相当慢。 - Dharman
你似乎在 preg_match_all 中忘记了 u 修饰符。 - Dharman
只有你的第一个解决方案似乎通过了我的单元测试:https://3v4l.org/OIZcM - Dharman
2
mb_str_split 在 PHP 7.4 中新增,并且它通过了我的单元测试:https://3v4l.org/M85Fi/rfc#output - Dharman
我的本地PHP Meetup要到周二才举行。那时我通常会了解任何新发布的信息。谢谢你告诉我。我有机会时会更新。 - mickmackusa
显示剩余3条评论

1
这对我很有帮助,它将Unicode字符串分解为字符数组:

这对我很有帮助,它将Unicode字符串分解为字符数组:

//
// split at all position not after the start: ^
// and not before the end: $, with unicode modifier
// u (PCRE_UTF8).
//
$arr = preg_split("/(?<!^)(?!$)/u", $text);

例如:

<?php
//
$text = "堆栈溢出";

$arr = preg_split("/(?<!^)(?!$)/u", $text);

echo '<html lang="fr">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
';

print_r($arr);

echo '</body>
</html>
';
?>

在浏览器中,它会生成这个:
Array ( [0] => 堆 [1] => 栈 [2] => 溢 [3] => 出 )

我很想更好地了解您的解决方案,请不要假设输出将用于HTML。 - Dharman
这个HTML浏览器输出仅用于显示utf8字符,因为某些控制台无法显示它们,但浏览器可以。 - jacouh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接