看板 C_and_CPP 關於我們 聯絡資訊
首先一個用語解釋: 在 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 選項 這樣你讀進來的字串就會跟輸入檔的編碼一模一樣了 -- 'Oh, Harry, don't you see?' Hermione breathed. 'If she could have done one thing to make absolutely sure that every single person in this school will read your interview, it was banning it!' ---'Harry Potter and the order of the phoenix', P513 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.195.9.46 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1521255424.A.D7E.html ※ 編輯: LPH66 (123.195.9.46), 03/17/2018 11:01:01
ilikekotomi: 感謝分享 沒想到windows的是這樣 03/17 11:12
EdisonX: 太感謝了!我先實作 , 有問題再請教,謝謝! 03/17 12:28
EdisonX: 再進一步請教 , 所以在監看式裡中文顯示亂碼也正常 ? 03/17 12:38
LPH66: 好久沒用 VS 的監看式, 剛剛測了一下 03/17 12:48
LPH66: char 陣列會用系統編碼顯示, 所以會有一樣的問題 03/17 12:48
EdisonX: 原來如此 , 那我放心全用 char* 去處理了, 謝謝. 03/17 12:56
Domos: utf-8是1~4byte,中文不一定都是3byte。utf-16則是2或4byt 03/17 13:01
Domos: e。 03/17 13:01
EdisonX: 那拿到一份文件有比較客觀的方法知道是用什麼編碼嗎 ? 03/17 13:02
EdisonX: 剛看了一下, 我的中文字確實有3bytes,應該是 utf8 了 03/17 13:38
LPH66: UTF-8 的中文確實不都是 3 byte, 但 4 byte 的中文是罕用字 03/17 13:41
LPH66: 所以我平常是都會直接只說 3 byte 這樣... 03/17 13:41
LPH66: 100% 判斷編碼的方法應該是沒有, 不過可以猜 03/17 13:42
LPH66: UTF-8 的位元組組合有個特定模式不容易在其他編碼出現 03/17 13:43
LPH66: 這也就是 Joel 在講的「根本就沒有純文字這種東西。」 03/17 13:45
LPH66: (src: http://tinyurl.com/cvultt ) 03/17 13:45
cutekid: 推 L 大附的補充連結。 03/17 13:48