2014-09-25 74 views
0

我可以看到一個Python字符串(不是Unicode字符串即U「」)輸入\xe4\xb8\xad\xe6\x96\x87這是中文更改爲\xe4\xb8\xad\xe6\xbf\xbf使用WE8MSWIN1252字符集使用的Oracle表中其列是CLOB存儲它(VARCHAR)和檢索它在Python後一個Web框架。我正在嘗試排查並理解低級別的情況。爲什麼在單字節字符集系統中不能存儲多個字節字符?

爲什麼會更改數據庫中的我的輸入 - 我認爲在發生的事情也出來?

我被告知,「這是因爲WE8MSWIN1252是單字節系統,它不支持多字節編碼」。這對我來說目前有點高層次的解釋。多字節仍然是3個字節。那麼,爲什麼不能WE8MSWIN1252系統分解成3個不同的字節說\xe6,\x96 and \x87店,並把它留給最終用戶來解釋呢?

這是什麼意思是說單字節編碼不能容納多個字節的系統?我在理解中失去了什麼?它的所有1和0。我們存儲位而不是Unicode等 - 這是更高層次的抽象?

+1

如果數據庫能夠執行字符集轉換,它必須保證進入的字符屬於您聲明的字符集。但'\ x96'和'\ xe7' [看起來是有效的字符](http://en.wikipedia.org/wiki/Windows-1252#Code_page_layout),所以問題必須存在於一些微妙的交互中。 – 2014-09-25 21:21:50

+0

_(96)‡(87)。你是否同意它不應該改變每個邏輯的輸入?讓Charset承擔其他事情。我沒有問題,因爲我可以在渲染時強制執行UTF-8。我可以看到第一個角色保持完美,因此期待第二個角色也這樣做。我至少希望能夠閱讀這個流,並強制執行一個utf-8來使其工作!我需要更深入地瞭解這一點,但至少你能澄清一下,如果你認爲你認爲這不應該純粹是在邏輯基礎上發生,並需要更多的研究?它更多地瞭解這一切。 – Nishant 2014-09-25 22:38:52

+1

數據庫不能只留下一些東西,因爲它保證了字符集轉換的能力。實際上,它可能會在進出途中進行轉換,併爲內部存儲使用一些不相關的字符集以保持一致性。無論它是否應該在這種特殊情況下工作都是無關緊要的,因爲abarnert已經提供了一個保證失敗的例子。 – 2014-09-25 22:48:31

回答

2

整點編碼字符串是你不是只是存儲位,你存儲字符串。根據Oracle數據庫,Oracle的Choosing a character set文檔準確解釋了這意味着什麼。

甲單字節編碼只知道如何表示(至多)256個不同的字符。如果你給它一個不同的字符,它不能代表它。它應該做什麼呢?

你的建議是,它應該採取一些其他編碼的表示,並假裝字節是在其自己的編碼字符。這不僅在概念上沒有意義,而且實際上也行不通 - 事實上,這正是mojibake的意義所在。

要採取的具體的例子,你有一個WE8MSWIN1252(大致相同編碼的Python調用CP1252)字符串列。你想存儲字符串'中文'。這沒有cp1252,但是它有一個UTF-8,它是'\xe4\xb8\xad\xe6\x96\x87'

那麼,如果你只是存儲了UTF-8字節好像他們是cp1252字符?那麼,這取決於數據庫如何定義代碼頁1252。最後兩個字節在原始代碼頁1252中不是有效的字符,但當前的Windows代碼頁1252確實將它們映射到字符。因此,如果數據庫按照IBM規則運行,它應該給你一個錯誤,或者用「無效字符」表示法替換字節(至少對於有這種事情的編碼); *如果它試圖模擬Windows,它。應該允許它**

爲了避免這個問題,讓我們把它簡單:如果您選擇什麼完整的256個字符的1 - 拉丁語系編碼?這會欺騙它讓你存儲數據。然後你會存儲字符串'中æ''ä¸\xadæ–‡'或類似的東西。這看起來不太有用。你可以編寫一個應用程序,這樣做是有道理的(因爲你知道你將通過Latin-1 mojibake重新編碼爲UTF-8到每一邊的真實字符串),但在這種情況下,爲什麼你要使用一個字符串首先?只需使用二進制列,並跳過整個Latin-1部分,應用程序就知道二進制數據表示UTF-8,而不是讓應用程序知道看起來像Latin-1的必須被記錄爲UTF-8有用。

甚至更​​簡單,只需用UTF-8列,或停止嘗試東亞文本存放在CP1252列...


*請參閱the docs甲骨文如何解釋替換字符,這比你想象的要複雜一些,與Python不一樣。

**您的數據庫調用的編碼WE8MSWIN1252的事實似乎暗示它應該是使用Windows定義;它將它們轉換爲0xBF的事實意味着它不是這樣做的。這很可能是合理的,因爲「MSWIN」意味着「MS Windows 3.1」或者地獄,即使是「MS Windows 1.0」,但我真的不知道。無論如何,正如下一段所解釋的那樣,這並不重要。如果要查看在「代碼頁1252」的任何含義下不應該合法的字符會發生什麼情況,請參閱試用'東京',即UTF-8中的'\xe6\x9d\xb1\xe4\xba\xac',並且0x9D在cp1252中有意留空。

+1

但是['\ x96' *是一個有效字符](http://en.wikipedia.org/wiki/Windows-1252#Code_page_layout)。 ''\ x96'.decode('cp1252')'返回'u'\ u2013'',它也可以用另一種方式工作。附:不是我不同意對數據庫撒謊是一個壞主意,它只是沒有解釋字面的例子。 – 2014-09-25 21:25:37

+0

@MarkRansom:謝謝;請查看新版本。我想過用一個例子說明_does_給出了一個錯誤(IIRC,東京的漢字呢?),但我認爲最好避開這個問題。你怎麼看? – abarnert 2014-09-25 21:32:07

+0

你說的一切都很有道理。我希望能找到Oracle爲'WE8MSWIN1252'假設的確切字符表,但是我的網絡搜索失敗了,而且我無法訪問Oracle來查看我自己。 – 2014-09-25 21:37:06