PHP - 包含 emojis/special 个字符的字符串长度
PHP - length of string containing emojis/special chars
我正在为移动应用程序构建 API,我似乎无法计算包含表情符号的字符串的长度。我的代码:
$str = "✌️ @mention";
printf("strlen: %d" . PHP_EOL, strlen($str));
printf("mb_strlen UTF-8: %d" . PHP_EOL, mb_strlen($str, "UTF-8"));
printf("mb_strlen UTF-16: %d" . PHP_EOL, mb_strlen($str, "UTF-16"));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("UTF-8", "UTF-16", $str)));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("ISO-8859-1", "UTF-16", $str)));
对此的回应是:
strlen: 27
mb_strlen UTF-8: 14
mb_strlen UTF-16: 13
iconv UTF-16: 14
iconv UTF-16: 27
但是我应该得到 17 作为结果。我们尝试计算 iOS、android 和 windows phone 上的字符串长度,到处都是 17。 iOS (swift) 片段:
var str = "✌️ @mention"
(str as NSString).length // 17
count(str) // 13
count(str.utf16) // 17
count(str.utf8) // 27
由于库的原因,我们需要使用 NSString。我需要这个来获得“@mention”的开始和结束位置。如果字符串仅包含文本或仅包含表情符号,则它可以正常工作,因此混合内容可能存在一些问题。
我做错了什么?我还能向你们提供哪些其他信息,让我朝着正确的方向前进?
谢谢!
你的函数都在计算不同的东西。
Graphemes: ✌ ️ @ m e n t i o n 13
----------- ----------- -------- --------------------- ------ ------ ------ ------ ------ ------ ------ ------ ------
Code points: U+1F44D U+1F3FF U+270C U+1F3FF U+FE0F U+0020 U+0040 U+006D U+0065 U+006E U+0074 U+0069 U+006F U+006E 14
UTF-16 code units: D83D DC4D D83C DFFF 270C D83C DFFF FE0F 0020 0040 006D 0065 006E 0074 0069 006F 006E 17
UTF-16-encoded bytes: 3D D8 4D DC 3C D8 FF DF 0C 27 3C D8 FF DF 0F FE 20 00 40 00 6D 00 65 00 6E 00 74 00 69 00 6F 00 6E 00 34
UTF-8-encoded bytes: F0 9F 91 8D F0 9F 8F BF E2 9C 8C F0 9F 8F BF EF B8 8F 20 40 6D 65 6E 74 69 6F 6E 27
PHP 字符串本身是字节。
strlen()
统计一个字符串的字节数:27.
mb_strlen(..., 'utf-8')
计算当使用 UTF-8 编码将字符串的字节解码为字符时,字符串中代码点(Unicode 字符)的数量:14.
(其他示例计数基本上没有意义,因为它们基于将输入字符串视为一种编码,而实际上它包含不同编码的数据。)
NSString 本身被计为 UTF-16 代码单元。有 17 个,而不是 14 个,因为上面的字符串包含像 </code> 这样的字符,不适合单个 UTF-16 代码单元,因此必须编码为代理项对。 PHP 中没有任何函数可以对 UTF-16 代码单元中的字符串进行计数,但是由于每个代码单元都被编码为两个字节,因此您可以通过编码为 UTF-16 并将字节数乘以二:</p>
<pre><code>strlen(iconv('utf-8', 'utf-16le', $str)) / 2
(注意:le
后缀是使 iconv
编码为 UTF-16 的特定字节顺序所必需的,并且不会通过选择一个并在开头添加 BOM 来弄乱计数说明它选择了哪一个字符串。)
我附上了一张图片来帮助说明@bobince 给出的答案。
本质上,所有 non-surrogate-pair 代码点在 UTF-16 中以两个字节结束,而所有 surrogate-pair 代码点以四个字节结束。如果我们将其除以二,我们将得到等效的预期长度值。
P.S。请原谅图片中的错误 "code points" 应该是 "code units"
我知道这是一个较老的问题,但我最近遇到了这个问题,这也可能对其他人有所帮助。
问题中的字符串:
$str = "✌️ @mention";
我希望它计数为 11:✌️
{2},space
{1},@
{1},mention
{7}
所以 2 + 1 + 1 + 7 = 11
PHP 的 intl
扩展有一个 grapheme_strlen()
函数,它以字素单位而不是字节或字符 (documentation)
获取字符串长度
<?php
$str = "✌️ @mention";
printf("strlen: %d" . PHP_EOL, strlen($str));
printf("mb_strlen UTF-8: %d" . PHP_EOL, mb_strlen($str, "UTF-8"));
printf("mb_strlen UTF-16: %d" . PHP_EOL, mb_strlen($str, "UTF-16"));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("UTF-8", "UTF-16", $str)));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("ISO-8859-1", "UTF-16", $str)));
printf("grapheme_strlen: %d" . PHP_EOL, grapheme_strlen($str));
PHP7.4 上的输出:
strlen: 27
mb_strlen UTF-8: 14
mb_strlen UTF-16: 13
PHP Notice: iconv_strlen(): Detected an illegal character in input string in php shell code on line 1
iconv UTF-16: 0
PHP Notice: iconv_strlen(): Detected an illegal character in input string in php shell code on line 1
iconv UTF-16: 0
grapheme_strlen: 11
我正在为移动应用程序构建 API,我似乎无法计算包含表情符号的字符串的长度。我的代码:
$str = "✌️ @mention";
printf("strlen: %d" . PHP_EOL, strlen($str));
printf("mb_strlen UTF-8: %d" . PHP_EOL, mb_strlen($str, "UTF-8"));
printf("mb_strlen UTF-16: %d" . PHP_EOL, mb_strlen($str, "UTF-16"));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("UTF-8", "UTF-16", $str)));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("ISO-8859-1", "UTF-16", $str)));
对此的回应是:
strlen: 27
mb_strlen UTF-8: 14
mb_strlen UTF-16: 13
iconv UTF-16: 14
iconv UTF-16: 27
但是我应该得到 17 作为结果。我们尝试计算 iOS、android 和 windows phone 上的字符串长度,到处都是 17。 iOS (swift) 片段:
var str = "✌️ @mention"
(str as NSString).length // 17
count(str) // 13
count(str.utf16) // 17
count(str.utf8) // 27
由于库的原因,我们需要使用 NSString。我需要这个来获得“@mention”的开始和结束位置。如果字符串仅包含文本或仅包含表情符号,则它可以正常工作,因此混合内容可能存在一些问题。
我做错了什么?我还能向你们提供哪些其他信息,让我朝着正确的方向前进?
谢谢!
你的函数都在计算不同的东西。
Graphemes: ✌ ️ @ m e n t i o n 13
----------- ----------- -------- --------------------- ------ ------ ------ ------ ------ ------ ------ ------ ------
Code points: U+1F44D U+1F3FF U+270C U+1F3FF U+FE0F U+0020 U+0040 U+006D U+0065 U+006E U+0074 U+0069 U+006F U+006E 14
UTF-16 code units: D83D DC4D D83C DFFF 270C D83C DFFF FE0F 0020 0040 006D 0065 006E 0074 0069 006F 006E 17
UTF-16-encoded bytes: 3D D8 4D DC 3C D8 FF DF 0C 27 3C D8 FF DF 0F FE 20 00 40 00 6D 00 65 00 6E 00 74 00 69 00 6F 00 6E 00 34
UTF-8-encoded bytes: F0 9F 91 8D F0 9F 8F BF E2 9C 8C F0 9F 8F BF EF B8 8F 20 40 6D 65 6E 74 69 6F 6E 27
PHP 字符串本身是字节。
strlen()
统计一个字符串的字节数:27.
mb_strlen(..., 'utf-8')
计算当使用 UTF-8 编码将字符串的字节解码为字符时,字符串中代码点(Unicode 字符)的数量:14.
(其他示例计数基本上没有意义,因为它们基于将输入字符串视为一种编码,而实际上它包含不同编码的数据。)
NSString 本身被计为 UTF-16 代码单元。有 17 个,而不是 14 个,因为上面的字符串包含像 </code> 这样的字符,不适合单个 UTF-16 代码单元,因此必须编码为代理项对。 PHP 中没有任何函数可以对 UTF-16 代码单元中的字符串进行计数,但是由于每个代码单元都被编码为两个字节,因此您可以通过编码为 UTF-16 并将字节数乘以二:</p>
<pre><code>strlen(iconv('utf-8', 'utf-16le', $str)) / 2
(注意:le
后缀是使 iconv
编码为 UTF-16 的特定字节顺序所必需的,并且不会通过选择一个并在开头添加 BOM 来弄乱计数说明它选择了哪一个字符串。)
我附上了一张图片来帮助说明@bobince 给出的答案。
本质上,所有 non-surrogate-pair 代码点在 UTF-16 中以两个字节结束,而所有 surrogate-pair 代码点以四个字节结束。如果我们将其除以二,我们将得到等效的预期长度值。
P.S。请原谅图片中的错误 "code points" 应该是 "code units"
我知道这是一个较老的问题,但我最近遇到了这个问题,这也可能对其他人有所帮助。
问题中的字符串:
$str = "✌️ @mention";
我希望它计数为 11:✌️
{2},space
{1},@
{1},mention
{7}
所以 2 + 1 + 1 + 7 = 11
PHP 的 intl
扩展有一个 grapheme_strlen()
函数,它以字素单位而不是字节或字符 (documentation)
<?php
$str = "✌️ @mention";
printf("strlen: %d" . PHP_EOL, strlen($str));
printf("mb_strlen UTF-8: %d" . PHP_EOL, mb_strlen($str, "UTF-8"));
printf("mb_strlen UTF-16: %d" . PHP_EOL, mb_strlen($str, "UTF-16"));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("UTF-8", "UTF-16", $str)));
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("ISO-8859-1", "UTF-16", $str)));
printf("grapheme_strlen: %d" . PHP_EOL, grapheme_strlen($str));
PHP7.4 上的输出:
strlen: 27
mb_strlen UTF-8: 14
mb_strlen UTF-16: 13
PHP Notice: iconv_strlen(): Detected an illegal character in input string in php shell code on line 1
iconv UTF-16: 0
PHP Notice: iconv_strlen(): Detected an illegal character in input string in php shell code on line 1
iconv UTF-16: 0
grapheme_strlen: 11