Big5 問號之謎:追查「?」亂碼的源頭
前言
最近同事問了一個問題:「為什麼畫面上看起來都是正常的,但是產出來的文字檔,空格的地方就是變成了問號,而且連續兩個空格,只有一個變成問號,另外一個是正常的」,客戶習慣使用UltraEdit開啟這些測試檔案,檢視內容是否正確的時候,向我們提出了這一個bug單,我們實際拿了notepad++看是正常的,狀況陷入了一團迷霧。
做了什麼確認?
使用UltraEdit開啟檔案
確實如使用者描述,連續空格處,只有一個空格變成了問號
使用NotePad++開啟檔案
直接開啟是正常的,但是嘗試將空格轉為其它顯示方式(Hex?手上只剩下Mac,請容我偷懶不去回憶這部分~XD)的時候,確實發現到兩格空格會轉為不同的內容。
從資料來源複製貼上到UltraEdit
使用資料庫的查詢軟體查詢後,複製貼上到UltraEdit,再轉為Hex(16進位)顯示
發現到分別是 20 和 C2 A0
撰寫測試
實際上查到這就已經破案了,因為使用者要求的串接系統只能接受big5編碼的檔案,因此在系統查詢完資料之後,將透過串接另一個系統的API呼叫取得的資料,轉為big5後產出。但是取得的文字內容是utf-8的編碼,由於big5並沒有不換行空格的編碼,所以無法識別,轉換的過程就變成一個問號了。
那再來就是寫一小段程式來確認是不是這樣 (可使用 jupyter 來執行看看)
1 |
|
上面程式假設字串來自於某個第三方服務的API,大多數的API回應都是使用UTF-8編碼,所以寫了一個包含utf-8不換行空格的字串 Hello ,my name is Mat.,實際上也是這次碰到的情況,連續兩個空格,但是一個是不換行空格,一個不是。
做一般想像中的replace的時候,可以發現到直接輸入空格替換是沒用的。後面又加上可能可以做的做法是使用正則表達式( \s )來尋找空白並取代為正常的空白(程式碼中使用變數 replaceString 取代,表示可取代成功),如果不想用正則,也可以使用 Char.IsWhiteSpace({inputChar}) 來一個一個Char檢查。
結論
其實不難想像到,這個問號的來源是來自於資料源系統在存入資料庫的時候,使用了textarea元素來送出資料到後端,後端程式接收到之後就直接存入資料庫中了,雖然外表上看起來都是空格,但還真的沒想過在前端這樣連續輸入兩個空格的時候,會變成一個不換行空格、一個正常空格。在更後端處理資料產出的系統在使用的時候,自然就會無條件相信來源系統資料,直接產出在大部分情況下都是沒什麼問題的,偏偏就是有幾個問號,請來源系統查,就是很正常的空白沒問題,但是來源系統使用的是網頁介面,編碼也都是直接使用UTF8,所以讓人充滿了困惑。
好在這個問題肯定是一堆人都碰過(尤其是中文圈,一堆死不更新,不用萬國編碼的系統),找出問題並沒有耗費太多的時間就找到資料。反而是想在C#中,輸出那一個不換行空白想了一下該怎麼做才能寫出來。