从string中删除非utf8字符
我有一个问题,从string中删除非UTF8字符,显示不正确。 字符是这样的0x97 0x61 0x6C 0x6F(hex表示)
删除它们的最好方法是什么? 正则expression式还是别的?
使用正则expression式的方法:
$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);
它searchUTF-8序列,并将其捕获到组1中。它还匹配单个字节,这些字节不能被识别为UTF-8序列的一部分,但不会捕获这些字节。 replace是捕获到组1中的任何内容。这样可以有效地删除所有无效的字节。
通过将无效字节编码为UTF-8字符,可以修复string。 但是,如果错误是随机的,这可能会留下一些奇怪的符号。
$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 != ""
似乎是最好的select。
我也加快了比赛。 它不是分别匹配每个字符,而是匹配有效的UTF-8字符序列。
如果将utf8_encode()
应用于已经是UTF8的string,它将返回一个乱码的UTF8输出。
我提出了解决所有这些问题的function。 这就是所谓的Encoding::toUTF8()
。
你不需要知道你的string的编码是什么。 它可以是Latin1(ISO8859-1),Windows-1252或UTF8,或者string可以混合使用。 Encoding::toUTF8()
将把所有东西都转换成UTF8。
我这样做是因为一个服务给了我所有的数据源,把这些编码混合在同一个string中。
用法:
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(),它将修复每个UTF8string,该string看起来被多次编码为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
下载:
你可以使用mbstring:
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
…将删除无效的字符。
请参阅: 通过问号replace无效的UTF-8字符,mbstring.substitute_character似乎被忽略
这是我的function,总是工作,无论编码:
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?
$text = iconv("UTF-8", "UTF-8//IGNORE", $text);
这是我正在使用的。 似乎工作得很好。 采取从http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/
UConverter可以使用自PHP 5.5以来。 如果您使用intl扩展名并且不使用mbstring,则UConverter是更好的select。
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可以用来删除无效的字节序列。 Hmlspecialchars比preg_match更好的处理大尺寸的字节和准确性。 可以看到很多使用正则expression式的错误实现。
function replace_invalid_byte_sequence3($str) { return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8')); }
尝试这个:
$string = iconv("UTF-8","UTF-8//IGNORE",$string);
根据iconv手册 ,函数将第一个参数作为input字符集,第二个参数作为输出字符集,第三个作为实际inputstring。
如果将input和输出字符集都设置为UTF-8 ,并将//IGNORE
标志附加到输出字符集,则该函数将删除(剥离)输出string中不能由输出字符集表示的所有字符。 因此,过滤inputstring是有效的。
文本可能包含非utf8字符 。 试着先做:
$nonutf8 = mb_convert_encoding($nonutf8 , 'UTF-8', 'UTF-8');
你可以阅读更多关于它在这里: http : //php.net/manual/en/function.mb-convert-encoding.php 新闻
$string = preg_replace('~&([az]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', htmlentities($string, ENT_COMPAT, 'UTF-8'));
我做了一个从string中删除无效的UTF-8字符的函数。 我使用它来清除27000产品的描述,然后生成XML导出文件。
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; }
从最近的补丁到Drupal的Feeds JSONparsing器模块:
//remove everything except valid letters (from any language) $raw = preg_replace('/(?:\\\\u[\pL\p{Zs}])+/', '', $raw);
如果你担心的是,它保留空格作为有效字符。
做了我需要的 它去掉了现在普遍使用的不符合MySQL'utf8'字符集的表情符号,并且给了我像“SQLSTATE [HY000]:一般错误:1366不正确的string值”的错误。
所以规则是第一个UTF-8 octlet将高位设置为一个标记,然后用1到4位来表示多less个额外的八进制; 那么每个附加的八进制都必须将高两位设置为10。
伪巨蟒将是:
newstring = '' cont = 0 for each ch in string: if cont: if (ch >> 6) != 2: # high 2 bits are 10 # do whatever, eg skip it, or skip whole point, or? else: # acceptable continuation of multi-octlet char newstring += ch cont -= 1 else: if (ch >> 7): # high bit set? c = (ch << 1) # strip the high bit marker while (c & 1): # while the high bit indicates another octlet c <<= 1 cont += 1 if cont > 4: # more than 4 octels not allowed; cope with error if !cont: # illegal, do something sensible newstring += ch # or whatever if cont: # last utf-8 was not terminated, cope
这同样的逻辑应该是可以转换到PHP。 但是,一旦你得到一个畸形的性格,还不清楚要做什么样的剥离。
要删除Unicode基本语言平面之外的所有Unicode字符:
$str = preg_replace("/[^\\x00-\\xFFFF]/", "", $str);
问题略有不同,但我所做的是使用HtmlEncode(string),
伪代码在这里
var encoded = HtmlEncode(string); encoded = Regex.Replace(encoded, "&#\d+?;", ""); var result = HtmlDecode(encoded);
input和输出
"Headlight\x007E Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?" "Headlight~ Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
我知道这不是完美的,但为我做的工作。
iconv:
http://php.net/manual/en/function.iconv.php
没有在PHP本身内部使用它,但它总是在我的命令行上performance良好。 你可以把它replace成无效的字符。