PHP - 从utf8字符串中快速删除浏览器中无法显示的所有字符的快捷方法

时间:2011-10-03 12:25:51

标签: php regex unicode utf-8 character-encoding

我有一个杂乱的数据库,其中包含世界各地许多机构的名称。

我想显示它们,包括国家字符,但没有无效字符 - 在firefox中显示为unicode数字。

如何过滤掉它们?

数据库有utf8编码,但是某些字符串插入了错误的编码,或者已经在源代码中出现问题。

我不想修复数据库 - 它太大了。我想过滤掉它 - “看不见了”

3 个答案:

答案 0 :(得分:6)

  

我想过滤掉它

您的数据有一个未指定的编码/字符集。这是一个很大的问题。

您可以先尝试将其转换为utf-8,然后删除所有不可打印的字符:

$str = iconv('utf-8', 'utf-8//ignore', $str);

echo preg_replace('/[^\pL\pN\pP\pS\pZ]/u', '', $str);

问题是,iconv功能只能尝试。它会丢弃任何无效的字符序列。从PHP 5.4开始,如果指定的输入编码无效,它将删除完整的字符串。

从PHP 5.3开始,您将看到警告输入字符串的编码无效。

您可以先删除所有无效utf-8字节序列来解决此问题:

$str = valid_utf8_bytes($str);

echo preg_replace('/[^\pL\pN\pP\pS\pZ]/u', '', $str);

/**
 * get valid utf-8 byte squences
 *
 * take over all matching bytes, drop an invalid sequence until first
 * non-matching byte.
 * 
 * @param string $str
 * @return string
 */
function valid_utf8_bytes($str)
{
    $return = '';
    $length = strlen($str);
    $invalid = array_flip(array("\xEF\xBF\xBF" /* U-FFFF */, "\xEF\xBF\xBE" /* U-FFFE */));

    for ($i=0; $i < $length; $i++)
    {
        $c = ord($str[$o=$i]);

        if ($c < 0x80) $n=0; # 0bbbbbbb
        elseif (($c & 0xE0) === 0xC0) $n=1; # 110bbbbb
        elseif (($c & 0xF0) === 0xE0) $n=2; # 1110bbbb
        elseif (($c & 0xF8) === 0xF0) $n=3; # 11110bbb
        elseif (($c & 0xFC) === 0xF8) $n=4; # 111110bb
        else continue; # Does not match

        for ($j=++$n; --$j;) # n bytes matching 10bbbbbb follow ?
            if ((++$i === $length) || ((ord($str[$i]) & 0xC0) != 0x80))
                continue 2
        ;

        $match = substr($str, $o, $n);

        if ($n === 3 && isset($invalid[$match])) # test invalid sequences
            continue;

        $return .= $match;
    }
    return $return;
}

答案 1 :(得分:1)

数据库可能不完全是问题 - 如果表是utf8编码的,那么它们中的字符串应该被转换(我认为)。我遇到的问题是正确确保编码是一致的。例如,默认情况下,mysqli连接器恢复为Latin-8859 IIRC,因此很可能在utf8中输出输出,utf8中的数据库仍然最终?字符,因为它们被mysqli连接器转换为拉丁语。

要确保全面的utf8,您需要执行以下操作:

在数据库中:

确保整理类似于utf8_general_ci

位于PHP视图文件的顶部:

<?php header('Content-Type:Text/Plain;charset=utf-8'); ?>

在HTML元标记中(可选):

<meta http-equiv="content-type" content="text/html;charset=utf-8" />

AND在数据库连接器中(以MySQLi为例):

mysqli::set_charset('utf8'); #note that for MySQL it isn't hyphenated

您可能会发现无论如何都能解决问题。

答案 2 :(得分:0)

如果数据库是你的情况下的问题(并且修复它就不在了),那么可能只是使用ORD打印出字符串中的每个字符,并找到不是控制字符的值好的。

然后,当您知道控制字符值时,将这些值传递给搜索该控制字符的函数,并尝试使用相应的UTF8字符更改utf-8编码(有缺陷的编码)。