我使用PHP来处理来自各种来源的文字。 我没有预料到它会比UTF-8,ISO-8859-1,或者WINDOWS-1252的任何其他。 如果这是任何其他比的一个,我只是需要确保文本被变成了一个有效的UTF-8字符串,即使字符都将丢失。 确实的iconv的// TRANSLIT选项解决这个问题? 例如,将这段代码确保字符串是安全的插入到UTF-8编码的文件(或数据库)?
function make_safe_for_utf8_use($string) {
$encoding = mb_detect_encoding($string, "UTF-8,ISO-8859-1,WINDOWS-1252");
if ($encoding != 'UTF-8') {
return iconv($encoding, 'UTF-8//TRANSLIT', $string);
} else {
return $string;
}
}
UTF-8可以存储任何Unicode字符。 如果你的编码是别的可言,包括ISO-8859-1或Windows 1252,UTF-8的每一个字符存储在里面。 所以,你不必担心,当您从任何其他编码字符串转换为UTF-8失去任何字符。
此外,两个ISO-8859-1和Windows 1252是单字节编码,其中任何一个字节是有效的。 这在技术上是不可能来区分它们。 我会选择Windows的1252作为非UTF-8序列默认的匹配,为不同的解码唯一字节0x80-0x9F范围。 这些解码各种字符,如在ISO 8859的智能引号和欧元在Windows 1252,而它们是几乎从来没有使用隐形控制字符。 Web浏览器有时会说,他们使用的是ISO-8859-1,但他们往往真的会使用Windows 1252。
将这段代码确保字符串是安全的插入到UTF-8编码的文件
你肯定会想设置可选的“严格”参数设置为TRUE此目的。 但我不知道这实际上涵盖了所有无效的UTF-8序列。 该功能不要求显式检查UTF-8有效性的字节序列。 目前已经知道的情况下mb_detect_encoding会前猜错UTF-8,虽然我不知道这是否仍然可以在严格模式下发生的。
如果你想确保,使用自己做W3推荐的正则表达式 :
if (preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \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', $string))
return $string;
else
return iconv('CP1252', 'UTF-8', $string);
随着MBSTRING库,你可以mb_check_encoding() 。
使用示例:
mb_check_encoding($string, 'UTF-8');
当性能问题, 这是比接受的答案提供的正则表达式更快。
在我的配置显示了一个快速测试(20000次迭代):
- 正则表达式:〜310ms
- mb_check_encoding:90毫秒〜
编辑
随着PHP 7.1.9一个新的Windows 10系统上, 正则表达式的解决方案优于mb_check_encoding()
对于任何字符串的长度(还是20000迭代):
- 10个字符:正则表达式=> 4ms的,
mb_check_encoding()
=> 64ms的 - 10000个字符:正则表达式=> 125ms的,
mb_check_encoding()
=> 2.4S
刚一说明:除了使用通常推荐(相当复杂)的由W3C正则表达式 ,你可以简单地使用“U”修饰符来测试UTF-8有效性的字符串:
<?php
if (preg_match("//u", $string)) {
// $string is valid UTF-8
}
看看http://www.phpwact.org/php/i18n/charsets了约字符集指南。 这个页面链接到一个页面专门为UTF8。
回答“是的iconv幂等”
也不是的iconv - 的iconv不幂等
函数utf8_encode()的iconv()之间的最大区别在于,可能的iconv提高这样的错误“检测到输入字符串不完整的多字节字符”即使有
的iconv( 'ISO-8859-1', 'UTF-8'。 '//忽略',$ STR)
在上面的代码:
$编码= mb_detect_encoding($字符串 “UTF-8,ISO-8859-1,WINDOWS-1252”);
你必须知道mb_detect_encoding可以回答UFT-8甚至是无效的UTF8字符串(格式错误的UTF8)
不知道这是否会达到同样的事情,但不能你只需要使用utf8_encode()
上的所有文本,而不用担心检测? 如果文本已经是UTF-8,它不会伤害它。 如果它不是,它将会被转换。 如果您已经想过这样做,是有一个原因,这不会为你工作?