PHP能够检测4字节编码的UTF-8字符吗?

20

我正在使用mysql 5.1服务器的utf8字符集mysql表,该服务器不支持表中的utf8mb4编码。 当插入4字节编码的utf8字符时,例如"","","","","","唧",""。 表格将弹出错误或跳过以下文本。

如何在PHP中以编程方式检测4字节编码的utf8字符并替换它们?


很简单:按字符(有多种方法)分割字符串,然后检查strlen($char)== 4。不确定这是否是检测MySQL无法处理的字符的正确方法,根据代码点可能更准确一些。 - deceze
你有查看过多字节扩展吗?此外,请务必阅读评论 - Sverri M. Olsen
抱歉重提一个这么旧的话题,但据我所知,你列出的字符不是4个字节,而是UTF8中的3个字节 ;) - codeling
@codeling 无论如何他们都需要4字节的容器。 :) 感谢您的信息! - Abby Chau Yu Hoi
@AbbyChauYuHoi,你的意思是他们在mysql中需要“utf8mb4”类型吗?我以为mysql中的“utf8”类型可以存储多达3个字节的字符?如果不行的话,我也得重新考虑我的当前工作 ;) - codeling
显示剩余4条评论
2个回答

19

以下正则表达式将替换4字节UTF-8字符:

function replace4byte($string, $replacement = '') {
    return preg_replace('%(?:
          \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
        | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
        | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
    )%xs', $replacement, $string);    
}

var_dump(replace4byte('d'), replace4byte('dd'));

这不依赖于/u修饰符,所以您不需要担心PCRE编译时的UTF-8。但是,如果您具有该支持,则deceze的preg_replace_callback更整洁。

(正则表达式改编自确保PHP中的有效UTF-8)


18

这应该可以运作:

if (max(array_map('ord', str_split($string))) >= 240) 

之所以如此是因为码点到U+FFFF的代码点被编码为形如1110xxxx 10xxxxxx 10xxxxxx的三个字节。更高的代码点具有11110xxx 10xxxxxx 10xxxxxx 10xxxxxx的形式,即最高字节的值为240或更高。如果字符串中存在任何这样的字节,则表示它是4字节序列的指示器。

如果您想要删除长字符,可以使用以下方法:

preg_replace_callback('/./u', function (array $match) {
    return strlen($match[0]) >= 4 ? null : $match[0];
}, $string)

虽然可能有更优雅的正则表达式方式来直接表示高代码点。


谢谢你的检测,但你能给一个替换的例子吗?$a = "omg, I cannot insert into my table, blahblahblah"; //目标 $a == "omg, I cannot insert MYTEXT into my table, blahblahblah"; - Abby Chau Yu Hoi

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