我有一个包含字段的表,其中包含MySQL数据库中的字符串。
MySQL版本是5.0.51a。表的默认字符集是'utf8'。
许多字符串都有unicode字符,例如\ xae和\ u21222(分别是注册符号和商标符号)。
例如,假设我有一个字段,其值为:
"Bing® Blang™ Blaow"
我的mysql命令行客户端的默认字符集是“latin1”。
如果我从命令行在mysql客户端程序中发出SELECT语句而没有指定字符集,则标题的输出显示如下:
"Bing® Blang Blaow"
(R)符号是正确的,但缺少(TM)符号。如果我将此字符串从控制台剪切并粘贴到TextMate中,则会出现(TM)符号,但在“Blang”一词中位于g后面的一半。
我假设中途背后的东西只是TextMate中的一个显示错误(尽管如果有人能够提供更好的细节,那将是很好的,但这不是真正重要的部分)。 / p>
我从它的剪切和粘贴行为中推断的主要原因是数据存在于数据库中,但某些字符集设置存在问题。
如果我在命令行上覆盖mysql客户端的默认编码,如下所示:
mysql --default-character-set=utf8
然后执行相同的选择,字符串出现为:
"Bing® Blang™ Blaow"
也就是说,(R)和(TM)符号都出现并且位于正确的位置,但两者前面都是unicode字符\ xae,它是一个A,顶部有一个回旋。
(顺便说一下,当我使用python将其拉出并在网页上显示时,这也是数据的显示方式,这就是我真正的问题所在。)
无论如何,这里发生了什么?我们最近所做的一切都尽可能地使用了UTF8,但是有可能在更改之前插入了一些这些行,这意味着它们一直在使用latin1默认值...但是这两种编码似乎都没有产生正确的结果?
如果在切换到utf8之前表上的默认编码是latin1时插入了行,那么编码被切换(通过alter table ..)然后编码实际上是否已经更新?其中一个编码现在应该有效吗? unicode会不会停止踢我的屁股?
答案 0 :(得分:2)
这里有很多问题:
关于字符
您指示文本包含字符U + AE和U + 2122(分别为®和™)。但是,结果意味着文本在“Blang”之后将U + 99作为字符:当你设置MySQL输出UTF8时,你会看到这个“™” - 这是显示在U + 99上的UTF8序列将此字节流解释为Windows-1252的终端。
U + 99可能不是你想要的:在Unicode中,这是一个没有图形表示的扩展控制字符。恰好在Windows-1252中,0x99是商标符号的编码(U + 2122)。
(请注意,当您选择Latin1时,MySQL和大多数Web浏览器都会出现使用Windows-1252的常见“破坏”行为。叹气。)
可能出现的问题
您的终端未使用正确的字符集。它显然在Windows-1252中运行。
程序应该以UTF-8连接到数据库。您可以在命令行中执行此操作,如您所见,或者在执行任何其他操作之前在数据库句柄中执行语句SET NAMES utf8_general_ci;
。其他一些数据库API可能有其他方法可以做到这一点,但所有SQL引擎都没有通用的方法。 SET NAMES ...
特定于MySQL,但一次设置所有必需的字符集变量(有三个!)。
将数据插入数据库的过程是在插入之前接受用户输入而未正确地将其从Windows-1252转换为UTF-8。这就是你将U + 99加入数据库的方法。由于我不知道你是如何获得这些数据的,我不知道该解决什么问题,但这里有几种可能性:
如果数据来自网页表单,请确保包含表单的页面以UTF-8格式提供,并正确标记(通过MIME类型和<meta>
标记。 )还要确保<form>
标记没有指定不同的字符集。
转换数据时,请确保使用 iconv 或类似的库将输入字符集转换为UTF-8。即使您认为输入是Latin1,也不要尝试手动执行此操作(例如,将每个字节扩展为16位,然后声称这是UTF-16 - 这对Windwos-1252不起作用!)。确保您知道源数据的字符集。特别是,一定要知道它是Latin1还是Windows-1252。
您可以使用用户输入的字符集连接到数据库,而只需插入用户输入的原始字节数据,而不是转换用户输入。但是,您必须确保只以这种方式进行插入:如果其他行具有无法在该字符集中表示的数据,则使用用户的字符集从数据中读回数据将丢失信息。可以建立一个MySQL连接,这样你就可以在一个字符集中发出语句并将结果读回另一个字符集......但它不适合胆小的人,未来的程序员可能会疯狂地试图理解为什么代码就是这样。
如果,当您使用Python提取数据并将其显示在网页中时,您会看到字符串“™”,这表明您正在以UTF格式正确地将数据从数据库中拉出-8,但随后将其放入未正确识别为UTF-8的网页中。可能它只是默认为Latin1,如上所述,它实际上是Windows-1252。
尽管如此,即使您修复了显示,请注意数据库中包含错误数据,因为U + 99实际上并不是UTF-8列中的商标符号。假设数据确实是Windows-1252,您需要通过读取所有数据并将U + 80到U + 9F范围内的任何字符替换为它们可能存在的内容来清理数据。如果你不确定数据最初是什么字符集 - 那么这个数据就是垃圾。
关于更改表格的字符集
在插入数据后转换表格的字符集和排序规则将转换列,但是,当然,任何已插入的数据都将丢失原始字符集无法表示的任何字符。
请注意ALTER TABLE foo CONVERT TO CHARACTER SET ...
和ALTER TABLE foo CHARACTER SET ...
之间的区别。后者只会更改表的默认字符集,并且不会更改任何列,即使它们已设置为默认创建时。 (MySQL仅在列创建时使用默认值,它不记得给定列是“默认”而不是它与表的默认值保持同步。)
答案 1 :(得分:1)
我认为它与Python代码中的mysql连接设置有关。 尝试设置conn.character_set_name或类似的东西,取决于你正在使用的mysql连接库。
如果是MySQLdb,它应该是这样的:
def character_set_name(*args, **kwargs): return 'utf-8' conn.character_set_name = new.instancemethod(character_set_name, conn, conn.__class__)
答案 2 :(得分:1)
是否有些列的字符集明显不同于表默认值?
答案 3 :(得分:1)
这样的事情......?
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci