我正在尝试将我们的数据库从latin1转换为UTF-8。不幸的是,我不能做一个大规模的单一切换,因为应用程序需要保持在线,我们有700GB的数据库要转换。
因此,我试图利用mysql的一些技巧,将表转换为UTF-8,而不是数据。我希望数据能够被实时读取、转换和替换。(如果愿意,可以进行JIT转换)
我们的php应用程序目前使用所有默认值,所以它使用latin1字符集连接到mysql,并丢弃在latin1中编码的UTF-8数据。当您使用latin1查看数据时,UTF-8字符会按预期显示。当您使用UTF-8查看数据时,事情会变得混乱。
因此,我建议强制mysql字符集为UTF-8,然后在必要时对数据进行及时转换。现在,鉴于cp1252/windows-1252是UTF-8的子集,检测cp1252/windows-1252编码并不是那么简单(就我所知)。
我编写了以下代码,试图检测cp1252/windows-1252编码并根据需要进行转换。它还应该检测正确编码的UTF-8字符,并且什么也不做。
$a = 'Card☃'; //cp1252 encoded
$a_test = '☃'.$a; //add known UTF8 character
$c = mb_convert_encoding($a_test, 'cp1252', 'UTF-8');
// attempt to detect known utf8 character after conversion
if (mb_strpos($c, '☃') === false) {
// not found, original string was not cp1252 encoded, so print
var_dump($a);
} else {
// found, original string was cp1252 encoded, remove test character and print
// This case runs
$c = mb_strcut($c, 1);
var_dump($c);
}
$a = 'COD☃'; //proper UTF8 encoded
$a_test = '☃'.$a; //add known UTF8 character
$c = mb_convert_encoding($a_test, 'cp1252', 'UTF-8');
// attempt to detect known utf8 character after conversion
if (mb_strpos($c, '☃') === false) {
// not found, original string was not cp1252 encoded, so print
// This case runs
var_dump($a);
} else {
// found, original string was cp1252 encoded, remove test character and print
$c = mb_strcut($c, 1);
var_dump($c);
}
运行此代码的输出为:
string 'Card☃' (length=7)
string 'COD☃' (length=6)
我知道,在数据库中的所有字符串上运行此操作都会对性能产生影响,这有待衡量,但如果我能在完全切换所有内容之前进行JIT转换,那么对我来说是值得的。
有人对如何优化这一点有什么建议吗?
首先,Windows-1252不是UTF-8的子集。你可以说ASCII是UTF-8的一个子集,但这通常更像是一场意识形态上的争论。
其次,不可能处理同时包含CP1252和UTF-8“字符”的字符串(实际上,对于CP1252,它是一个字节,对于Unicode,它是一个代码点)。您可以尝试将其读取为CP1252,并将所有Unicode字符视为单个字节,也可以将其读取为UTF-8,并删除任何无效的字节序列(如果CP1252字符与Unicode代码点匹配,则创建随机字符)。您没有使用$c=mb\u struct($c,1)删除测试字符
,您正在删除由mb_convert_编码创建的问号,因为它无法将该Unicode字符转换为CP1252字符。
第三,永远不要转换字符串,然后在事实发生后尝试确定编码。转换第二个测试字符串后,它是
?鳕鱼
。没有理由检查其中是否存在Unicode字符,因为您已将其转换为CP1252。里面不能有Unicode字符。作为程序员,您必须知道输出是什么。
唯一的解决方案是检查字符串是否为CP1252,将违规字符转换为占位符,然后将该字符串转换为Unicode:
function convert_cp1252_to_utf8($input, $default = '', $replace = array()) {
if ($input === null || $input == '') {
return $default;
}
// https://en.wikipedia.org/wiki/UTF-8
// https://en.wikipedia.org/wiki/ISO/IEC_8859-1
// https://en.wikipedia.org/wiki/Windows-1252
// http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
$encoding = mb_detect_encoding($input, array('Windows-1252', 'ISO-8859-1'), true);
if ($encoding == 'ISO-8859-1' || $encoding == 'Windows-1252') {
/*
* Use the search/replace arrays if a character needs to be replaced with
* something other than its Unicode equivalent.
*/
/*$replace = array(
128 => "€", // http://www.fileformat.info/info/unicode/char/20AC/index.htm EURO SIGN
129 => "", // UNDEFINED
130 => "‚", // http://www.fileformat.info/info/unicode/char/201A/index.htm SINGLE LOW-9 QUOTATION MARK
131 => "ƒ", // http://www.fileformat.info/info/unicode/char/0192/index.htm LATIN SMALL LETTER F WITH HOOK
132 => "„", // http://www.fileformat.info/info/unicode/char/201e/index.htm DOUBLE LOW-9 QUOTATION MARK
133 => "…", // http://www.fileformat.info/info/unicode/char/2026/index.htm HORIZONTAL ELLIPSIS
134 => "†", // http://www.fileformat.info/info/unicode/char/2020/index.htm DAGGER
135 => "‡", // http://www.fileformat.info/info/unicode/char/2021/index.htm DOUBLE DAGGER
136 => "ˆ", // http://www.fileformat.info/info/unicode/char/02c6/index.htm MODIFIER LETTER CIRCUMFLEX ACCENT
137 => "‰", // http://www.fileformat.info/info/unicode/char/2030/index.htm PER MILLE SIGN
138 => "Š", // http://www.fileformat.info/info/unicode/char/0160/index.htm LATIN CAPITAL LETTER S WITH CARON
139 => "‹", // http://www.fileformat.info/info/unicode/char/2039/index.htm SINGLE LEFT-POINTING ANGLE QUOTATION MARK
140 => "Œ", // http://www.fileformat.info/info/unicode/char/0152/index.htm LATIN CAPITAL LIGATURE OE
141 => "", // UNDEFINED
142 => "Ž", // http://www.fileformat.info/info/unicode/char/017d/index.htm LATIN CAPITAL LETTER Z WITH CARON
143 => "", // UNDEFINED
144 => "", // UNDEFINED
145 => "‘", // http://www.fileformat.info/info/unicode/char/2018/index.htm LEFT SINGLE QUOTATION MARK
146 => "’", // http://www.fileformat.info/info/unicode/char/2019/index.htm RIGHT SINGLE QUOTATION MARK
147 => "“", // http://www.fileformat.info/info/unicode/char/201c/index.htm LEFT DOUBLE QUOTATION MARK
148 => "”", // http://www.fileformat.info/info/unicode/char/201d/index.htm RIGHT DOUBLE QUOTATION MARK
149 => "•", // http://www.fileformat.info/info/unicode/char/2022/index.htm BULLET
150 => "–", // http://www.fileformat.info/info/unicode/char/2013/index.htm EN DASH
151 => "—", // http://www.fileformat.info/info/unicode/char/2014/index.htm EM DASH
152 => "˜", // http://www.fileformat.info/info/unicode/char/02DC/index.htm SMALL TILDE
153 => "™", // http://www.fileformat.info/info/unicode/char/2122/index.htm TRADE MARK SIGN
154 => "š", // http://www.fileformat.info/info/unicode/char/0161/index.htm LATIN SMALL LETTER S WITH CARON
155 => "›", // http://www.fileformat.info/info/unicode/char/203A/index.htm SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
156 => "œ", // http://www.fileformat.info/info/unicode/char/0153/index.htm LATIN SMALL LIGATURE OE
157 => "", // UNDEFINED
158 => "ž", // http://www.fileformat.info/info/unicode/char/017E/index.htm LATIN SMALL LETTER Z WITH CARON
159 => "Ÿ", // http://www.fileformat.info/info/unicode/char/0178/index.htm LATIN CAPITAL LETTER Y WITH DIAERESIS
);*/
if (count($replace) != 0) {
$find = array();
foreach (array_keys($replace) as $key) {
$find[] = chr($key);
}
$input = str_replace($find, array_values($replace), $input);
}
/*
* Because ISO-8859-1 and CP1252 are identical except for 0x80 through 0x9F
* and control characters, always convert from Windows-1252 to UTF-8.
*/
$input = iconv('Windows-1252', 'UTF-8//IGNORE', $input);
if (count($replace) != 0) {
$input = html_entity_decode($input);
}
}
return $input;
}
诀窍是,您必须检查ISO-8859-1和CP1252,因为它们非常相似。在玩了几个小时这个功能后,我艰难地发现了这一点,只有这个答案救了我。如果你发现这个函数很有用,请选择1。
基本上,这个函数用表示Unicode字符的HTML实体替换所有那些坏的CP1252字节。然后,我们将字符串从
ISO-8859-1
/CP1252
转换为UTF-8
,而我们的新Unicode字符都没有损坏,因为它们是简单的ASCII字符。最后,我们对HTML实体进行解码,最终得到一个100%的Unicode字符串。
我试图保存一个字符串在希伯来文文件,同时有文件ANSI编码。恐怕所有的尝试都失败了。 PHP文件本身是UTF-8 这是我正在尝试的代码: 由于某种原因,返回false。 另一次尝试是: 这返回一个空字符串。当这不起作用时,将输出字符集更改为Windows-1255的工作。所以函数本身工作,但由于某种原因,它不转换为1252。 我运行这个函数之前和之后的和打印的结果 在图标之前编码是UTF-8,在图
我有UTF-8源数据,我必须创建在Windows 1252字符编码编码的CSV文件。 我尝试了经典功能,但效果不佳。它必须支持转换后的塞尔维亚字符: "čćžšđ" 。 此外,我还尝试转换为CP1252、ISO-8859-1、ISO-8859-2,功能包括:mb_convert_编码、iconv和iconv_set_编码。 有人知道该试试什么吗?
我正在编写一个PERL脚本,它从一个数据库中读取数据。XLSX Excel文件,并将数据插入Oracle数据库。数据库采用Windows-1252编码,excel文件采用UTF-8编码(据我所知,这是xlsx文件的标准),特殊字符如ö、ü、ű、ő显示为??。正确的转换方法是什么。xlsx文件?在将读取的字符串插入数据库之前,我曾尝试将其转换为windows-1252,并尝试将整个Excel文件转换
在我的Silverlight应用程序中,我得到了一个用windows-1252编码的XML文件。现在我的问题,它不会正确显示,直到Windows-1252字符串转换为UTF8字符串。在一个正常的C#环境中,这不会是一个大问题:在那里我可以做这样的事情: (将字符串的字符编码从windows-1252转换为utf-8) 但是silverlight不支持windows-1252,它只支持unicode
将编码传递到UTF-8后,我无法在Windows-1252中显示字符串。 我被迫在init中转换为UTF-8 我想将我的字符串转换为Windows-1252字符以显示它: 我正在得到这个结果 如何获得正确的以下结果? 谢谢! 当做
我有一个旧数据库,声称已将排序规则设置为windows-1252,并将文本字段的内容存储为 当它显示在遗留的网络应用程序中时,它在浏览器中显示为。浏览器报告一个UTF-8编码的页面。我不知道这种转换是如何完成的(几乎可以肯定的是,它不是通过动态搜索和替换完成的)。这对我来说是个问题,因为我将文本字段(和许多其他类似的字段)从遗留数据库中取出,并放入一个新的UTF-8数据库。新的Web应用程序将新数