【问题标题】:preg_match does not find a UTF-8 character at the beginning of a binary string which contain non-UTF8 characterspreg_match 在包含非 UTF8 字符的二进制字符串的开头找不到 UTF-8 字符
【发布时间】:2019-11-05 08:42:21
【问题描述】:

如果字符串中某处是非 UTF8 字符,带有修饰符 u 的 preg_match 将返回 false 以表示错误。 例如:

<?php
$string = "ABCD\xc3";
$r = preg_match('/^./u',$string, $match);
var_dump($r);  //bool(false)

这个例子你自己试试:https://3v4l.org/qkHl4

如果非UTF8字符在末尾被删除,则正则表达式查找第一个字符。

$string = "ABCD";
$r = preg_match('/^./u',$string, $match);
var_dump($r, $match); 
//int(1) array(1) { [0]=> string(1) "A" }

对于还包含非 UTF8 字符的字符串,是否有一种简单的方法可以使用正则表达式来识别开头的 UTF-8 字符?

【问题讨论】:

  • 对于第一个示例,我还期望找到字符“A”。我怀疑 preg_match 在使用正则表达式之前首先检查整个字符串是否所有字符都是 UTF-8。
  • 根据这个answer你可以使用mb_convert_encoding删除无效的utf字符
  • 如果您的字符串不是有效的 UTF-8,为什么要使用 u 模式并期望它能够工作......?
  • 这个“\u{c3}”是一个UTF-8字符“Ô,这个“\xc3”不是一个UTF-8字符。我的字符串也包含非 UTF8 字符。
  • 如果您的字符串包含“非 UTF-8 字符”,则它不是有效的 UTF-8/Unicode 字符串,u 预计并且仅适用于 UTF-8 字符串。你要么有一个有效的 UTF-8 字符串,然后可以在上面使用 Unicode 正则表达式,要么你没有,你不能。

标签: php regex utf-8 preg-match


【解决方案1】:

您也可以考虑使用T-Regx,它以更协作的方式处理 UTF8 错误:

try {
    pattern('^.', 'u')->match("ABCD\xc3")->all();
catch (SafeRegexException $e) {
    // handle
}

【讨论】:

    【解决方案2】:

    基于此answer,您可以使用mb_convert_encoding 删除无效的utf 字符:

    $string = "ABCD\xc3";
    $string = mb_convert_encoding($string, 'UTF-8', 'UTF-8');
    $r = preg_match('/^./u', $string, $match);
    var_dump($r, $match);
    

    给出以下结果:

    int(1)
    array(1) {
      [0] =>
      string(1) "A"
    }
    

    【讨论】:

    • 不幸的是,对我没有帮助。带有 mb_convert_encoding 的行将所有非 UTF8 替换为“?”。所以我不能说第一个字符是否是有效的 UTF-8。注意:要以十六进制表示法解析转义字符,如何将字符串“\xc3”括在双引号 (") 中。
    【解决方案3】:

    我想经过长时间的搜索,我自己找到了答案。

    修饰符 u 仅在整个字符串是有效的 UTF-8 字符串时才起作用。 即使只找到第一个字符,也会首先检查整个字符串。 修饰符 u 不能用于此问题。但是,可以使用正则表达式。

    function utf8Char($string){
        $ok = preg_match(
          '/^[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]
          |^[\xE0-\xEF][\x80-\xBF][\x80-\xBF]
          |^[\xC0-\xDF][\x80-\xBF]
          |^[\x00-\x7f]/sx',
          $string,
          $match);
        return $ok ? $match[0] : false;      
    }
    
    
    var_dump(utf8char("€a\xc3def"));  //string(3) "€"
    var_dump(utf8char("a\xc3def"));  //string(1) "a"
    var_dump(utf8char("\xc3def"));  //bool(false)
    

    可以使用 substr 函数检索非 UTF8 字节。

    var_dump(substr("\xc3def",0,1)); //string(1) "�"
    

    【讨论】:

      猜你喜欢
      • 2016-07-01
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 2011-09-30
      • 1970-01-01
      • 2018-11-05
      相关资源
      最近更新 更多