在UTF8和Latin1表中将ISO-8859-1数据转换为UTF-8

5

问题概述:

在尝试将具有mysql数据库的网站从latin1转换为utf8时,尽管确保了所有字符集都是utf8系统范围内,但某些特殊字符仍无法正确显示。

问题详情:

这是一个常见的问题。但我似乎增加了一些复杂性。

多年前,一个糊涂的开发人员(我)用MySQL组建了一个网站。其中一些表使用了latin1_swedish_ci和utf8_general_ci。所有输入/显示都通过具有iso-8859-1字符集的页面完成。

现在,我需要将所有这些数据转换为utf-8,并统一编码。然而,我在两种情况下都遇到了一些特殊字符的问题(即:ü)。这些字符在UTF-8页面上似乎无法正确显示。它们显示为�。当在mysql查询浏览器中查看utf8表中的数据时,正确输入的utf8'd 'u'会显示为一些特殊字符,而不正确的latin1'u'则会像应该出现在页面上一样显示。但它没有。

我尝试了许多方法:

  1. Percona脚本:https://github.com/rlowe/mysql_convert_charset
  2. 将列转换为二进制,然后转换为utf8
  3. 将utf8表转换为latin,然后重复上述过程

似乎没有什么方法可以解决数据问题。

倒出整个数据库并进行重要操作并不是一个可行的选择,因为它现在是一个庞大的数据库,而且停机时间很短。

更新(2013年10月22日)

我采纳了@deceze的建议,并根据http://kunststube.net/frontback/中的所有内容编码区域进行了审查。我确实发现一些仍在使用latin1传递/编码数据的地方。所以,我现在已经全部改成了UTF-8。然而,在一个表中,这个数据仍然不能正确显示。在一个utf8的表中(没有列有隐式编码),field1是在latin1中。我可以通过运行以下命令来确认这一点,从而正确地显示文本:

从我的表中选择convert(cast(convert(field1 using latin1) as binary) using utf8),其中id = 1

这将把Hahnemühle转换为Hahnemühle。

在field2中,数据似乎采用不同的(未知)编码方式。当在field2上使用上述查询时,Hahnem�hle被转换为Hahnem�hle。我已经浏览了http://dev.mysql.com/doc/refman/5.5/en/charset-charsets.html上的所有字符集,但没有一个能正确输出数据。


你到底遇到了哪些“问题”?这些字符是否正确地存储在它们各自的列中?当您在一个不错的管理界面中查看它们时,它们是否看起来像它们应该的那样,还是已经混乱了?除非您试图将非Latin1字符存储在Latin1列中,否则迄今为止这些列的设置并不重要。 latin1列只能存储由Latin-1定义的256个字符,除此之外,在日常使用中并不重要。如果您使用正确的连接编码插入数据,则不应存在任何问题。 - deceze
1
不是“列排序规则”,而是连接编码。请阅读在Web应用程序中全面处理Unicode以获取该概念的概述。 - deceze
如果浏览器显示一个“�”,那就意味着它试图解释你发送的任何内容为UTF-8,但实际上你并没有发送UTF-8。如果你将连接编码设置为数据库的utf8,你应该会得到UTF-8编码的数据,无论它存储在你的列中。在整个链路中,从数据库→PHP→浏览器,数据被转换成了不是UTF-8的东西。根据所提供的信息,无法告诉你具体在哪里出了问题。 - deceze
@deceze 这就是我认为它与数据有关的原因。 - David
请展示字符串的bin2hex($string)值以及应该显示的文本。 - deceze
显示剩余11条评论
3个回答

5
在MySQL中将一列设置为latin1,将其他列设置为utf8是完全可以的。在这里没有问题需要解决。这个字符集参数仅影响数据的内部存储。这也意味着,你不能将“漢字”等非Latin-1字符存储在latin1列中。但是,如果假设你只是在那里存储“Latin-1字符”,那就没问题了。
MySQL有一个通常称为连接编码的东西。它告诉MySQL你从PHP(或其他地方)发送给它的文本的编码方式,以及当从MySQL检索数据时希望返回的编码方式。列字符集、"输入连接编码"和"输出连接编码"都可以是不同的东西,MySQL将根据需要动态转换编码。
因此,假设你到目前为止已经使用了正确的连接编码,并且数据已经正确存储在你的数据库中,并且你没有尝试将非Latin-1字符存储在Latin-1列中,那么你只需要执行以下操作来更新你的列字符集为UTF-8:
ALTER TABLE table MODIFY column TEXT [...] CHARACTER SET utf8;

5
您可以尝试使用mysqldump将编码从ISO-8859-1转换为utf-8:
mysqldump --user=username --password=password --default-character-set=latin1 --skip-set-charset dbname > dump.sql
chgrep latin1 utf8 dump.sql (or when you prefer  sed -i "" 's/latin1/utf8/g' dump.sql) 
mysql --user=username --password=password --execute="DROP DATABASE dbname; CREATE DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;"
mysql --user=username --password=password --default-character-set=utf8 dbname < dump.sql

对于sed的小技巧和备选的chgrep方法表示+1,作为奖励。 - Stephane Gosselin

3

在将字符串显示在页面上之前,可以对其应用utf8_encode来消除“glyph”字符(�)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接