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