我在从字符串中删除非UTF-8字符方面遇到了问题,这些字符无法正确显示。这些字符的表示形式如0x97 0x61 0x6C 0x6F(十六进制表示)。
最好的方法是什么?使用正则表达式还是其他什么?
我在从字符串中删除非UTF-8字符方面遇到了问题,这些字符无法正确显示。这些字符的表示形式如0x97 0x61 0x6C 0x6F(十六进制表示)。
最好的方法是什么?使用正则表达式还是其他什么?
utf8_encode()
,它将返回一段乱码的UTF8输出。Encoding::toUTF8()
。Encoding::toUTF8()
将把一切都转换为UTF8。require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::toUTF8($mixed_string);
$latin1_string = Encoding::toLatin1($mixed_string);
我已经包含了另一个函数,Encoding::fixUTF8(),它将修复每个看起来像是被多次编码成UTF8后出现乱码的字符串。
用法:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
示例:
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
将输出:
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
下载:
使用正则表达式方法:
$regex = <<<'END'
/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
){1,100} # ...one or more times
)
| . # anything else
/x
END;
preg_replace($regex, '$1', $text);
它搜索UTF-8序列,并将其捕获到第1组中。它还匹配无法识别为UTF-8序列的单个字节,但不会捕获这些字节。替换为捕获到第1组中的内容。这有效地删除了所有无效字节。$regex = <<<'END'
/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
){1,100} # ...one or more times
)
| ( [\x80-\xBF] ) # invalid byte in range 10000000 - 10111111
| ( [\xC0-\xFF] ) # invalid byte in range 11000000 - 11111111
/x
END;
function utf8replacer($captures) {
if ($captures[1] != "") {
// Valid byte sequence. Return unmodified.
return $captures[1];
}
elseif ($captures[2] != "") {
// Invalid byte of the form 10xxxxxx.
// Encode as 11000010 10xxxxxx.
return "\xC2".$captures[2];
}
else {
// Invalid byte of the form 11xxxxxx.
// Encode as 11000011 10xxxxxx.
return "\xC3".chr(ord($captures[3])-64);
}
}
preg_replace_callback($regex, "utf8replacer", $text);
编辑:
!empty(x)
将匹配非空值("0"
被视为空)。x != ""
将匹配非空值,包括"0"
。x !== ""
将匹配除""
以外的任何内容。在这种情况下,x != ""
似乎最好使用。
我还加快了匹配速度。它不再逐个字符匹配,而是匹配有效UTF-8字符序列。
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
...将删除无效的字符。
<0x1a>
。 - Alliswell<0x1a>
虽然不是可打印字符,但它是一个完全有效的UTF-8序列。你可能会遇到非可打印字符的问题?查看这个链接:https://dev59.com/cnM_5IYBdhLWcg3w43pt - Maxime Pacaryini_set('mbstring.substitute_character', 'none');
,否则结果中会出现问号。 - cby016"\xFF"
,那就是无效的 UTF-8。 - hanshenrikmb_convert_encoding()
移除,就像OP所要求的那样(我不确定完全理解你的意思?) - Maxime Pacary这个函数可以删除所有非ASCII字符,它很有用但不能解决问题:
这是我的函数,无论编码如何都可以正常工作:
function remove_bs($Str) {
$StrArr = str_split($Str); $NewStr = '';
foreach ($StrArr as $Char) {
$CharNo = ord($Char);
if ($CharNo == 163) { $NewStr .= $Char; continue; } // keep £
if ($CharNo > 31 && $CharNo < 127) {
$NewStr .= $Char;
}
}
return $NewStr;
}
它是如何工作的:
echo remove_bs('Hello õhowå åare youÆ?'); // Hello how are you?
í
字符,它是一个有效的UTF-8字符参见表格。教训是:不要相信API错误消息 :) - Valentine Shimb_str_split()
和 mb_ord()
来获取正确的 CharNo。 - MrMacvos$text = iconv("UTF-8", "UTF-8//IGNORE", $text);
这是我正在使用的代码。看起来工作得非常好。取自http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/
试试这个:
$string = iconv("UTF-8","UTF-8//IGNORE",$string);
根据iconv手册所述,该函数将把第一个参数作为输入字符集,第二个参数作为输出字符集,第三个参数作为实际输入字符串。//IGNORE
标志,则该函数将从输入字符串中删除(去除)所有无法由输出字符集表示的字符。因此,实际上对输入字符串进行了过滤。//IGNORE
,但似乎无法抑制无效的 UTF-8 通知(当然,我知道这个问题,并想要修复它)。手册中一条评分很高的评论似乎认为这是一个已经存在了几年的 bug。 - halfericonv
。@halfer,也许你的输入数据不是来自 utf-8。另一个选项是将其重新转换为 ascii,然后再次转换为 utf-8。在我的情况下,我使用了 iconv
,如 $output = iconv("UTF-8//", "ISO-8859-1//IGNORE", $input );
。 - m3nda嗨,你可以使用简单的正则表达式
$text = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $text);
它将从字符串中截断所有非UTF-8字符
这段文字可能包含非UTF8编码字符。首先尝试:
$nonutf8 = mb_convert_encoding($nonutf8 , 'UTF-8', 'UTF-8');
你可以在这里阅读更多信息:http://php.net/manual/en/function.mb-convert-encoding.php[news][2]
自PHP 5.5开始,可以使用UConverter。如果您使用intl扩展且不使用mbstring,则最好选择UConverter。
function replace_invalid_byte_sequence($str)
{
return UConverter::transcode($str, 'UTF-8', 'UTF-8');
}
function replace_invalid_byte_sequence2($str)
{
return (new UConverter('UTF-8', 'UTF-8'))->convert($str);
}
自 PHP 5.4 起,可以使用 htmlspecialchars 函数来删除无效字节序列。和 preg_match 相比,htmlspecialchars 处理字节大小和准确性更好,尤其在处理大型字节时表现更佳。我们经常发现有很多错误的正则表达式实现方式。
function replace_invalid_byte_sequence3($str)
{
return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8'));
}
我已经编写了一个函数,可以从字符串中删除无效的UTF-8字符。在生成XML导出文件之前,我使用它来清除27000个产品的描述。
public function stripInvalidXml($value) {
$ret = "";
$current;
if (empty($value)) {
return $ret;
}
$length = strlen($value);
for ($i=0; $i < $length; $i++) {
$current = ord($value{$i});
if (($current == 0x9) || ($current == 0xA) || ($current == 0xD) || (($current >= 0x20) && ($current <= 0xD7FF)) || (($current >= 0xE000) && ($current <= 0xFFFD)) || (($current >= 0x10000) && ($current <= 0x10FFFF))) {
$ret .= chr($current);
}
else {
$ret .= "";
}
}
return $ret;
}
ord()
返回的结果在0-255范围内。这个函数中的巨大的 if
语句测试了 ord()
永远不会返回的 Unicode 范围。如果有人能够澄清这个函数为什么会这样工作,我将非常感激。 - i336_