2009-08-07 81 views
2

我有一个字段包含我的MySQL数据库中的字符串表。我在MySQL中的这个unicode字段出了什么问题?

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中只是一个显示错误(尽管如果任何人都可以提供更好的细节,但这不是真正的重要部分)。

我从它的剪切后粘贴行为中推断出的主要原因是数据在数据库中,但某些地方的某种字符集设置有问题。

如果我覆盖了mysql客户端的默认编码,像这样的命令行:

mysql --default-character-set=utf8 

然后做同样的选择,串出来的:

"Bing® Blang™ Blaow" 

这是(R)和(TM)符号都出现在正确的位置,但两者之前都是unicode字符\ xae,它是一个顶部带有回音的A。 (顺便说一下,这也是我使用python将其展示出来并显示在网页上时显示的数据的方式,这是我真正的问题所在)。

无论如何,这里发生了什么?我们最近做的所有事情都使用了UTF8,但有可能在改变之前插入了其中的一些行,这意味着它们会使用latin1默认值......但是这两种编码似乎都不会产生正确的结果?

如果在表格上的默认编码是latin1时插入行,然后切换到utf8,那么编码已切换(通过alter table ..),那么编码是否会实际更新?如果其中一种编码现在可以工作? unicode会停止踢我的屁股?

+0

相关:http:// stackoverflow .com/questions/1219003 /奇怪字符在mysql-dbase/ – random 2009-08-07 02:58:09

回答

2

有相当多的问题在这里:

关于字符

您表示文本具有字符U + AE和U + 2122(分别为®和™)。但是,结果意味着文本在“Blang”之后的字符为U + 99:当您将MySQL设置为输出UTF8时,您会看到这个“™” - 这是显示在U + 99上的UTF8序列终端将该字节流解释为Windows-1252。

U + 99可能不是你想要的:在Unicode中,这是一个没有图形表示的扩展控制字符。恰巧在Windows-1252中,0x99是商标符号(U + 2122)的编码。

(请注意,MySQL和大多数Web浏览器都具有一个共同的, “破” 使用的是Windows 1252的行为,当你选择Latin1的。唉。)

什么可能是错误

  1. 您的终端未在正确的字符集中运行。它显然在Windows-1252中运行。

  2. 程序应该以UTF-8连接到数据库。你可以在命令行中做到这一点,就像你发现的那样,或者在做其他事情之前在你的数据库句柄中执行语句SET NAMES utf8_general_ci;。其他一些数据库API可能有其他方式来执行此操作,但对于所有SQL引擎没有通用的方式。 SET NAMES ...特定于MySQL,但一次设置所有必需的字符集变量(有三个!)。

  3. 将数据插入到数据库中的过程是在插入之前将用户输入并未正确将其从Windows-1252转换为UTF-8。这就是你如何得到一个U + 99到你的数据库。因为我不知道你是如何获得这些数据做什么,我不知道要解决什么,但这里有几种可能性:

    1. 如果数据来自网页的形式,一定要与页面表单以UTF-8格式提供,正确标记为(通过MIME类型和<meta>标签。)另请确保<form>标签未指定不同的字符集。

    2. 转换数据时,请确保使用iconv或类似的库将输入字符集转换为UTF-8。即使你认为输入是Latin1,也不要试图手动完成(例如,将每个字节零扩展为16位,然后声称这是UTF-16 - 这对于Windwos-1252不起作用!)。确保你知道源数据的字符集。特别是,一定要知道它是否为Latin1或Windows-1252。

    3. 除了转换用户输入外,还可以用用户输入的字符集连接数据库,然后插入从用户处获得的原始字节数据。但是,您必须确保仅以这种方式进行插入操作:如果其他行中的数据不能在该字符集中表示,则将数据从用户的字符集中读回数据将丢失信息。可以建立一个MySQL连接,以便在一个字符集中发布语句,并将结果读回另一个字符集中。但这不是因为内心微弱,未来的程序员可能会努力去理解为什么代码这样做。

  4. 如果,当你拉出来的数据使用Python和在网页中显示它,你看到的字符串“a™”,然后就是表明您正确把数据从数据库中作为UTF-8,但随后将其放入未正确标识为UTF-8的网页中。可能这仅仅是拉丁文1的默认值,如上所述,拉丁文文件确实是Windows-1252。

  5. 尽管如此,即使您修复了显示,请注意数据库中的数据不正确,因为U + 99在UTF-8列中并不是真正的商标符号。假设数据真的是Windows-1252,你需要清理你的数据,读取所有数据,并将U + 80到U + 9F范围内的任何字符替换为它们可能已经存在的字符。如果你不确定数据原本是什么字符集的话 - 那么这个数据只是垃圾。

关于更改字符集表

  1. 插入数据转换列后转换表的字符集和整理,但是,当然,已经插入的任何数据都会有已经丢失了原始字符集无法表示的任何字符。

  2. 要小心,要注意ALTER TABLE foo CONVERT TO CHARACTER SET ...ALTER TABLE foo CHARACTER SET ...后来只改变默认字符表中设置之间的差异,并不会改变任何列,即使它们被设置为在创建缺省值。 (MySQL只在列创建时使用默认值,它不记得给定的列是“默认”的,不会保持它与表的默认同步)。

1

我认为它与你的Python代码中的mysql连接的设置有关。 尝试设置conn.character_set_name或类似的东西,取决于你正在使用的MySQL连接库。

在MySQLdb的情况下,它应该smthng这样的:

 
def character_set_name(*args, **kwargs): return 'utf-8' 
conn.character_set_name = new.instancemethod(character_set_name, conn, conn.__class__) 
+0

我将字符集设置为utf8在python连接 - 在这一点上我主要是肯定,如果我能弄清楚发生了什么事命令行我可以在我的代码中获得正确的结果 - 但我仍然不清楚在基本DB /命令行级别发生了什么。 – John 2009-08-07 04:30:25

1

会不会是某些列有明确不同的字符集,比默认的表?

+0

这种情况。我不确定如何根据这些知识来解决问题,但我认为这是主要问题。 – John 2009-08-07 18:15:19

1

像这样的东西...?

ALTER TABLE tbl_name转换为字符集是utf8 COLLATE utf8_general_ci

+0

这确实是我所要做的,因为我提到的问题导致我在Scott McClung的回答中发现了我的评论,但没有解决mtnviewmark所描述的实际问题。 – John 2009-08-10 22:14:53

+0

不适用于我.. – 2015-02-24 05:02:35