2009-08-07 42 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