0

所以我在 PHP 中寻找一种正确的方法来检测字符串是否在 BMP 范围内(基本多语言平面),但我什么也没找到。在这种特殊情况下,甚至mb-check-encodingmb_detect_encoding也没有提供任何帮助。

所以我写了自己的代码

<?php

function is_bmp($string) {
    $str_ar = mb_str_split($string);
    foreach ($str_ar as $char) {
        /*Check if there's any character's code point outside the BMP range*/
        if (mb_ord($char) > 0xFFFF)
            return false;
    }
    return true;
}

/*String containing non-BMP Unicode characters*/
$string = 'blah blah';
var_dump(is_bmp($string));
?>

输出:

布尔(假)

现在我的问题是:

有更好的方法吗?它有什么缺陷吗?

4

2 回答 2

1

如果你有一个正确的 UTF-8 编码输入字符串,你可以检查它的字节以确定它是否有 BMP 之外的符号。

从字面上看,你需要检测:输入字符串是否包含任何符号,哪个码位大于 0xFFFF(即大于 16 位)

注意UTF-8 编码的工作原理

  • 代码00x7F的代码点按原样编码。一个字节。
  • 所有其他代码点都有一个0xC0 ... 0xFF范围内的代码作为第一个字节,它还编码了后面有多少额外的字节。并将0x80...0xBF编码为附加字节。

要编码 0x10000 或更大的代码点,UTF-8 需要 4 个字节的序列,并且该序列的第一个字节将是0xF0或更大。在所有其他情况下,整个字符串将包含小于 0xF0 的字节。

简而言之,您的任务只是找到:字符串的二进制表示是否包含范围为 0xF0...0xFF 的任何字节?

function is_bmp($string) {
   return preg_match('#[\xF0-\xFF]#', $string) != 0;
}

或者

更简单(但在速度上可能不太有效),您可以使用 PCRE 处理 UTF-8 序列的能力(请参阅选项 PCRE_UTF8):

function is_bmp($string) {
   return preg_match('#[^\x00-\x{FFFF}]#u', $string) != 0;
}
于 2019-08-01T13:46:23.847 回答
1
var_dump(
    !preg_match('/[^\x0-\x{ffff}]/u', 'blah blah')
);
于 2019-08-01T13:40:01.067 回答