Re: [問題] UTF-8 Read / Write

作者: LPH66 (-6.2598534e+18f)   2018-03-17 10:57:02
首先一個用語解釋:
在 Windows 系統之下, 所有的 "Unicode" 都特指 UTF-16LE 編碼
這其實跟 Windows 內部的實作有關 (其實就是 Windows 的 wchar_t 字串啦)
跟我們平常其他討論裡的 Unicode 是指稱那個抽象編碼的用語不一樣
以下為分別兩者, Windows 的 "Unicode" 我會加 "" 表示
※ 引述《EdisonX (卡卡獸)》之銘言:
: 開發平台(Platform): (Ex: Win10, Linux, ...)
: Visual Studio 2017 , Console C/C++
: 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
: 問題(Question):
: [Q1]
: 目前我收到的檔案,用記事本開、notepad++開,
: 一般 asci 是用 1 byte , 繁中、簡中(非常少數)是用 2 byte 存,
: 再用記事本去開,預設是用 utf-8 存 (非 asci),且無 bom 檔頭 ,
: 所以我是否可以假設這份檔案是以 utf-8 方式存檔?
UTF-8 的中文是 3-byte 喔
2-byte 的中文 Unicode 是 UTF-16
至於 Windows 預設的記事本, 只要不是存成 "ANSI" 選項就一定會加 BOM
當中的 "Unicode" 同樣是指 UTF-16
(記事本的 "Unicode" 是 UTF-16LE, "Unicode Big Endian" 是 UTF-16BE)
Notepad++ 我沒用過不太清楚 (我自己是用 Notepad2)
不過這種第三方的軟體才比較有可能設定成沒有 BOM 的存檔
: [Q2]
: 目前我嚐試過用 fopen / _wfopen 方式去開、讀檔 ,
: 也試過指定 ccs=UTF-8 方式去開 ,
: 再做簡單的 printf / wprintf , 不論怎麼改跑出來的一直都是亂碼 ,
: 最後嚐試用 char , 直接輸出到檔案去 , 神奇的事發生了
: console 輸出是亂碼 , 檔案全都解得出來
: 去細節後 code 摘要如下
: FILE * fin = fopen(sfilename.c_str(), "rb,ccs=UTF-8");
: char * pBuf = (char *)malloc(filesize + 32);
: fread((void*)pBuf, 1, filesize, fin);
: pBuf[filesize] = 0;
: FILE * fout = fopen("output.txt", "w");
: pFind = pBuf;
: while (pFind = strstr(pFind, pszDesc)) {
: pFindNext = strstr(pFind + iDescLen, pszScore);
: if (pFindNext == NULL) break;
: *(pFindNext - 1) = 0;
: fprintf(stdout, "%s\n", pFind); \\ 亂碼
: fprintf(fout, "%s\n", pFind); \\ 正常
: pFind = pFindNext + 1;
: }
: fclose(fout);
: free(pBuf);
: 請問是不是我誤會了什麼東西?
: 若要解析這種檔案, 請問我的方法正確嗎?
: 另若有版友建議直接加入 ATL CString 處理編碼的話也請告知
: (乍看只換 CString 問題應該不會改善)
如推文所說, console 是系統編碼, 在繁中系統就是 950
所以你把 Unicode 字串原封不動輸出是一定會變成亂碼的 (不論什麼編碼)
至於 ccs 選項, 它是你指定說這檔案是什麼編碼
系統來幫你轉成 "Unicode" 字串這樣
進來之後就已經是 "Unicode" ie. UTF-16LE 編碼的字串了
也就是你的 pBuf 已經是一個 UTF-16LE 編碼字串
你可以檢視一下你的 output.txt 的編碼, 會發現它是 UTF-16LE 無 BOM
: [Q3]
: 最後的問題是 , 這些截出來的字串會丟到簡易型 db,
: 之前碰過 sqlite , 但只用過 asci 編碼 , 查了下官網 ,
: sqlite 應是支援 utf-8 , 請問這方面是否有人有過經驗能給些意見?
: 或是直接丟掉 sqlite , 有其他較簡易但字元編碼較佳的 sql lib ?
: 最後謝謝各位細心回覆,感激不盡。
所有資料庫對字串欄位都必須指定編碼
那麼這裡問題來了: 你的字串如上面所說是一個 UTF-16LE 的字串
你不能就這樣貿貿然把它一股腦兒塞到指定為 UTF-8 的資料庫欄位當中
如果你要沿著這條路線下去的話, 你的資料庫欄位必須要指定為 UTF-16LE 才對
====
那如果你想保持輸入檔的 UTF-8 格式的話
還有一個方式是你叫 Windows 不要幫你轉, 也就是拿掉 ccs 選項
這樣你讀進來的字串就會跟輸入檔的編碼一模一樣了
作者: ilikekotomi (Young)   2018-03-17 11:12:00
感謝分享 沒想到windows的是這樣
作者: EdisonX (卡卡獸)   2018-03-17 12:28:00
太感謝了!我先實作 , 有問題再請教,謝謝!再進一步請教 , 所以在監看式裡中文顯示亂碼也正常 ?
作者: LPH66 (-6.2598534e+18f)   2018-03-17 12:48:00
好久沒用 VS 的監看式, 剛剛測了一下char 陣列會用系統編碼顯示, 所以會有一樣的問題
作者: EdisonX (卡卡獸)   2018-03-17 12:56:00
原來如此 , 那我放心全用 char* 去處理了, 謝謝.
作者: Domos (沒事發發廢文)   2018-03-17 13:01:00
utf-8是1~4byte,中文不一定都是3byte。utf-16則是2或4byte。
作者: EdisonX (卡卡獸)   2018-03-17 13:02:00
那拿到一份文件有比較客觀的方法知道是用什麼編碼嗎 ?剛看了一下, 我的中文字確實有3bytes,應該是 utf8 了
作者: LPH66 (-6.2598534e+18f)   2018-03-17 13:41:00
UTF-8 的中文確實不都是 3 byte, 但 4 byte 的中文是罕用字所以我平常是都會直接只說 3 byte 這樣...100% 判斷編碼的方法應該是沒有, 不過可以猜UTF-8 的位元組組合有個特定模式不容易在其他編碼出現這也就是 Joel 在講的「根本就沒有純文字這種東西。」(src: http://tinyurl.com/cvultt )
作者: cutekid (可愛小孩子)   2018-03-17 13:48:00
推 L 大附的補充連結。

Links booklink

Contact Us: admin [ a t ] ucptt.com