Exp*_*lls 5 mysql character-encoding
我发现我还不明白这一点,这让我很生气,但也许一些解释会有所帮助。这是一个由两部分组成的问题,但希望这两部分都很小并且直接相关:
\n\n我们最近遇到一个问题,内容是将U+00a0(不间断空格)字符插入具有字符集的数据库列中latin1。SELECT只需在列中打印出“\xc3\x82”即可。我不确定这是选择的产物还是展示的产物,但我相信是前者。 SELECT BINARY col相反,它会打印出“\xc2\xa0”,因为我的 shell 有$LANG = en_US.utf8.
一个更明显的例子是“\xc3\xa2\xe2\x80\x9e\xc2\xa2”与“\xe2\x84\xa2”
\n\n使用SELECT CONVERT(col USING utf8)still 打印出“\xc3\x82”和“\xc3\xa2\xe2\x80\x9e\xc2\xa2”——我不一定希望它有不同的做法,但问题源于何处?是存储时出现的问题吗?有没有办法让 UTF8 显示从数据库中出来,而不是依赖 UI 来正确显示(如果这有意义的话?)
为了尝试自己重现此问题,我执行了以下操作:
\n\nCREATE TABLE chrs (\n lat varchar(255) charset latin1,\n utf varchar(255) charset utf8\n);\nINSERT INTO chrs VALUES (\'\xe2\x84\xa2\', \'\xe2\x84\xa2\');\nINSERT INTO chrs VALUES (\'\xc2\xa0\', \'\xc2\xa0\'); -- U+00a0\nRun Code Online (Sandbox Code Playgroud)\n\n然而,这会导致:
\n\n> SELECT * FROM chrs;\n+------+------+\n| lat | utf |\n+------+------+\n| \xe2\x84\xa2 | \xe2\x84\xa2 |\n| \xc2\xa0 | \xc2\xa0 |\n+------+------+\nRun Code Online (Sandbox Code Playgroud)\n\n我希望lat显示“\xc3\x82”和“\xc3\xa2\xe2\x80\x9e\xc2\xa2”,所以显然有一些我不明白的东西。
更重要的是:
\n\n > SELECT BINARY lat, BINARY utf FROM chrs;\n+------------+------------+\n| BINARY lat | BINARY utf |\n+------------+------------+\n| \xef\xbf\xbd | \xe2\x84\xa2 |\n| \xef\xbf\xbd | \xc2\xa0 |\n+------------+------------+\nRun Code Online (Sandbox Code Playgroud)\n\n这表明这些值未正确存储(?)到lat.
我注意到那SELECT @@character_set_client是utf8,所以我将其更改为latin1并再次插入空格,但这会产生
| \xc3\x82\xc2\xa0 | \xc3\x82\xc2\xa0 |\nRun Code Online (Sandbox Code Playgroud)\n\n对于两列。 SELECT BINARY lat正确显示空格,但SELECT binary utf8仍打印出“\xc3\x82”。我希望该专栏能够更utf8正确地工作。
charset列上的 实际在存储/显示方面有何作用?简而言之,您的数据库似乎没问题,除非您通过将 [@@character_set_client] 从 [utf8] 更改为 [latin1] 来明确告诉它表现奇怪。否则,我认为您会看到使用 UTF-8 与 Windows-1252 的软件组件之间在其他地方存在分歧的影响。
\n\n我们如何理解正在发生的事情?
\n\n首先,我们回想一下,在 MySQL 中 latin1 实际上意味着 Windows-1252,这种编码与“Latin-1”本身略有不同,也称为 ISO/IEC 8859-1。
\n\n现在让我们考虑以下有关商标符号和不间断空格的数据:
\n\nWindows 1252 十六进制字节:8D
字符:“不间断空格”
出现问题的各种方式:
\n\n看来,当您插入时,数据库将商标符号存储在“latin1”中作为十六进制字节 8D,在“UTF-8”中存储为十六进制字节 E2 A4 A2。它将不间断空格存储在“latin1”中作为十六进制字节“A0”,在UTF-8中存储为十六进制字节C2 A0。当您以交互方式执行正常的 SELECT 操作时,“latin1”商标符号首先会转换为 Unicode 点 U+2122,然后转换为 UTF-8 十六进制字节 E2 84 A2,最终可能会被误解为 Windows-1252 字节。
\n\n在哪里可以找到上面显示的有关字符的数据:
\n\n