我知道在不同的字符集之间存在一个古老的字符编码问题,但是我被困在一个与Window的“曲线引号”相关的问题上。
我们有一个客户喜欢将数据复制并粘贴到文本字段中,然后将其发布到我们的应用上。该数据通常会包含卷曲引号。我曾经使用以下方法将它们转换为正常的对应物:
function convert_smart_quotes($string) {
$badwordchars=array("\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c", "\xe2\x80\x9d", "\xe2\x80\x93", "\xe2\x80\x94", "\xe2\x80\xa6");
$fixedwordchars=array("'", "'", '"', '"', '-', '--', '...');
return str_replace($badwordchars,$fixedwordchars,$string);
}
这个工作好几个月了。然后经过一些更改(我们切换服务器,对系统进行更新,升级PHP等等),我们知道它不再起作用了。所以,我看看,我了解到“卷曲引号”都变成了不同的字符。在这种情况下,他们将变成以下内容:
“=¡È
“=¡É
'=¡Æ
'=¡Ç
这些字符在保存在数据库中时会显示为被诅咒的“黑钻石问号符号”。 mySQL数据库位于latin1_swedish_ci中,接收消息的应用程序也是如此。所以,虽然我知道utf-8更好,但它必须保留在latin1_swedish_ci或ISO-8859-1中,否则我们将不得不重建所有内容......这是不可能的。
我的网页和表单均以utf-8发布。如果我将其更改为ISO-8859-1,则引号会成为问号。
我已经尝试在字符串中搜索“¡È”或“¡É”的出现并用正常引号替换它们,但我无法让它工作。我通过在上面的函数中添加以下内容来实现它:
$string = str_replace("xa1\xc8", '"', $string);
$string = str_replace("xa1\xc9", '"', $string);
$string = str_replace("xa1\xc6", "'", $string);
$string = str_replace("xa1\xc7", "'", $string);
我已经被困在这几个小时了,并且无法在网上找到任何真正的帮助。你可以想象,googleing“¡É”并没有带来非常具体的反应。
感谢任何指导!
答案 0 :(得分:8)
您的问题是您接受用户的UTF-8输入,然后将其插入数据库,就像它是Latin1(ISO-8859-1)一样。 (请注意,latin1_swedish_ci
不是编码,而是整理(对于Latin1)。请参阅this SO question on the difference。以解决您的角色编码问题,整理并不重要。)
您应该使用强大的方法将UTF-8字符串转换为Latin1,例如iconv
,而不是手动识别重要的UTF-8序列并替换它们。
请注意,这是有损转换:Latin1中不存在某些UTF-8字符(如引号)。你可以选择忽略这些字符(用空字符串替换它们,或者用其他东西替换它们),或者你可以选择音译它们(用等效的替代它们替换它们) ,就像"
的卷曲引语一样......但如果有人在表单中放置金
,你会怎么做?
iconv
会尝试在可能的位置进行音译:
// convert from utf8 to latin1, approximating out of range characters
// by the closest latin1 alternative where possible (//TRANSLIT)
$latinString = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $utf8String);
(您也可以将其配置为忽略所有超出范围的字符 - 有关详细信息,请参阅iconv
's documentation。)
如果您不想添加新库,PHP还附带utf_decode
函数:
$latinString = utf_decode($utf8String);
然而,PHP的设计并没有考虑多个字符编码,因此我更倾向于远离处理编码的(有时是错误的)标准库函数。
答案 1 :(得分:3)
您可以使用以下代码来解决此问题。
$str = mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8');
或
$str = mb_convert_encoding($str, 'HTML-ENTITIES', 'auto');
可以在php文档网站上找到更多信息。