作者LPH66 (J∪$т М㎝iκä)
看板C_and_CPP
标题Re: [问题] UTF-8 Read / Write
时间Sat Mar 17 10:57:02 2018
首先一个用语解释:
在 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://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1521255424.A.D7E.html
※ 编辑: LPH66 (123.195.9.46), 03/17/2018 11:01:01
1F:推 ilikekotomi: 感谢分享 没想到windows的是这样 03/17 11:12
2F:推 EdisonX: 太感谢了!我先实作 , 有问题再请教,谢谢! 03/17 12:28
3F:→ EdisonX: 再进一步请教 , 所以在监看式里中文显示乱码也正常 ? 03/17 12:38
4F:→ LPH66: 好久没用 VS 的监看式, 刚刚测了一下 03/17 12:48
5F:→ LPH66: char 阵列会用系统编码显示, 所以会有一样的问题 03/17 12:48
6F:推 EdisonX: 原来如此 , 那我放心全用 char* 去处理了, 谢谢. 03/17 12:56
7F:推 Domos: utf-8是1~4byte,中文不一定都是3byte。utf-16则是2或4byt 03/17 13:01
8F:→ Domos: e。 03/17 13:01
9F:推 EdisonX: 那拿到一份文件有比较客观的方法知道是用什麽编码吗 ? 03/17 13:02
10F:→ EdisonX: 刚看了一下, 我的中文字确实有3bytes,应该是 utf8 了 03/17 13:38
11F:→ LPH66: UTF-8 的中文确实不都是 3 byte, 但 4 byte 的中文是罕用字 03/17 13:41
12F:→ LPH66: 所以我平常是都会直接只说 3 byte 这样... 03/17 13:41
13F:→ LPH66: 100% 判断编码的方法应该是没有, 不过可以猜 03/17 13:42
14F:→ LPH66: UTF-8 的位元组组合有个特定模式不容易在其他编码出现 03/17 13:43
15F:→ LPH66: 这也就是 Joel 在讲的「根本就没有纯文字这种东西。」 03/17 13:45
17F:推 cutekid: 推 L 大附的补充连结。 03/17 13:48