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

看板C_and_CPP作者 (J∪$т М㎝iκä)時間6年前 (2018/03/17 10:57), 6年前編輯推噓6(6011)
留言17則, 5人參與, 6年前最新討論串2/2 (看更多)
首先一個用語解釋: 在 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

03/17 11:12, 6年前 , 1F
感謝分享 沒想到windows的是這樣
03/17 11:12, 1F

03/17 12:28, 6年前 , 2F
太感謝了!我先實作 , 有問題再請教,謝謝!
03/17 12:28, 2F

03/17 12:38, 6年前 , 3F
再進一步請教 , 所以在監看式裡中文顯示亂碼也正常 ?
03/17 12:38, 3F

03/17 12:48, 6年前 , 4F
好久沒用 VS 的監看式, 剛剛測了一下
03/17 12:48, 4F

03/17 12:48, 6年前 , 5F
char 陣列會用系統編碼顯示, 所以會有一樣的問題
03/17 12:48, 5F

03/17 12:56, 6年前 , 6F
原來如此 , 那我放心全用 char* 去處理了, 謝謝.
03/17 12:56, 6F

03/17 13:01, 6年前 , 7F
utf-8是1~4byte,中文不一定都是3byte。utf-16則是2或4byt
03/17 13:01, 7F

03/17 13:01, 6年前 , 8F
e。
03/17 13:01, 8F

03/17 13:02, 6年前 , 9F
那拿到一份文件有比較客觀的方法知道是用什麼編碼嗎 ?
03/17 13:02, 9F

03/17 13:38, 6年前 , 10F
剛看了一下, 我的中文字確實有3bytes,應該是 utf8 了
03/17 13:38, 10F

03/17 13:41, 6年前 , 11F
UTF-8 的中文確實不都是 3 byte, 但 4 byte 的中文是罕用字
03/17 13:41, 11F

03/17 13:41, 6年前 , 12F
所以我平常是都會直接只說 3 byte 這樣...
03/17 13:41, 12F

03/17 13:42, 6年前 , 13F
100% 判斷編碼的方法應該是沒有, 不過可以猜
03/17 13:42, 13F

03/17 13:43, 6年前 , 14F
UTF-8 的位元組組合有個特定模式不容易在其他編碼出現
03/17 13:43, 14F

03/17 13:45, 6年前 , 15F
這也就是 Joel 在講的「根本就沒有純文字這種東西。」
03/17 13:45, 15F

03/17 13:45, 6年前 , 16F
03/17 13:45, 16F

03/17 13:48, 6年前 , 17F
推 L 大附的補充連結。
03/17 13:48, 17F
文章代碼(AID): #1Qh8G0r- (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1Qh8G0r- (C_and_CPP)