读取Unicode文件

4

我读取和使用unicode文件内容时遇到了问题。

我正在使用一个unicode发布版本,并尝试从一个unicode文件中读取内容,但数据包含奇怪的字符,我似乎找不到将数据转换为ASCII的方法。

我正在使用fgets。我尝试过fgetwsWideCharToMultiByte以及其他一些在其他文章和帖子中找到的函数,但都没有成功。


4
你可能需要澄清你所说的“Unicode”的意思。是指UTF-8吗?UTF-16呢? - Williham Totland
1
如果您发布相关代码并告诉我们您看到的结果与您的期望有何不同,这将会很有帮助。 - Nick Meyer
3
请注意,您的文件中的“奇怪字符”可能没有ASCII表示。 - Kim Gräsman
1
一个文件不是Unicode,它是Unicode的某种编码(例如UTF-8或Latin-1)。这个文件的编码是什么? - Kathy Van Stone
6个回答

7
因为您提到了WideCharToMultiByte,我会假设您在处理Windows相关的事情。
“从Unicode文件中读取内容...找到一种将数据转换为ASCII的方法”可能会有问题。如果您将Unicode转换为ASCII(或其他旧代码页),则会冒着损坏/丢失数据的风险。由于您正在“使用Unicode发布版本”,因此您需要读取Unicode并保持Unicode。
因此,您的最终缓冲区将必须是wchar_t(或WCHAR、CStringW,相同的东西)。
因此,您的文件可能是utf-16或utf-8(utf-32非常罕见)。对于utf-16,字节序也很重要。如果有BOM,那会帮助很多。
快速步骤:
  • 使用wopen_wfopen作为二进制文件打开文件
  • 读取前几个字节以识别BOM编码
  • 如果编码是utf-8,则读入一个字节数组,并使用WideCharToMultiByteCP_UTF8将其转换为wchar_t
  • 如果编码是utf-16be(big endian),则读入wchar_t数组并使用_swab
  • 如果编码是utf-16le(little endian),则读入wchar_t数组即可完成

此外(如果您使用较新的Visual Studio),您可以利用_wfopen的MS扩展。它可以将编码作为模式的一部分(类似于_wfopen(L"newfile.txt", L"rw, ccs=<encoding>");,其中编码为UTF-8或UTF-16LE)。它还可以根据BOM检测编码。

警告:要跨平台存在问题,wchar_t可以是2或4个字节,转换例程不可移植...

有用的链接:


这正是这条信息的含义:“如果您将Unicode转换为ASCII(或其他遗留代码页),则会面临损坏/丢失数据的风险”。 - Mihai Nita
抱歉,我的评论应该作为回答问题的答案发布。你的答案是正确的。 - DaveE

1

处理字符集的预期方式是让区域设置系统来处理。

在打开流之前,您必须设置正确的区域设置。

另外,您标记了问题为C++,但您写了有关fgets和fgetws而不是IOStreams;您的问题是C ++还是C?

C语言:

#include <locale.h>
setlocale(LC_ALL, ""); /* at least LC_CTYPE */

对于C++

#include <locale>
std::locale::global(std::locale(""));

如果您的环境正确设置了Unicode,则宽IO(wstream,fgetws)应该可以正常工作。如果没有,则必须更改您的环境(对于Windows,我不知道它是如何工作的;对于Unix,设置LC_ALL变量是一种方法,请参见locale -a以获取支持的值)。或者,将空字符串替换为区域设置也可以,但这样您就在程序中硬编码了区域设置,您的用户可能不会欣赏。

如果您的系统不支持足够的区域设置,在C++中有可能自己编写转换facet。但这超出了本答案的范围。


1

为了回答这个问题,我们需要更多的信息(例如,您是要将Unicode文件读入char缓冲区还是wchar_t缓冲区?文件使用什么编码?),但现在您可能想确保您不会遇到this issue,如果您的文件是Unicode并且您正在文本模式下使用fgetws

当Unicode流I/O函数以文本模式操作时,源或目标流被认为是一系列多字节字符。因此,Unicode流输入函数将多字节字符转换为宽字符(如同调用mbtowc函数一样)。出于同样的原因,Unicode流输出函数将宽字符转换为多字节字符(如同调用wctomb函数一样)。


1

Unicode 是将数字代码映射为字符的过程。在 Unicode 之前的步骤是文件的编码:如何将一些连续的字节转换为数字代码?您必须检查文件是否以大端、小端或其他方式存储。

通常,BOM(字节顺序标记)被写入文件的前两个字节:FF FE 或 FE FF。


0

首先:我假设您正在尝试读取UTF8编码的Unicode(因为您可以读取一些字符)。例如,您可以在Notpad++中检查此信息。

对于您的问题-我建议使用某种库。您可以尝试 QT, QFile支持Unicode(以及库的其余部分)。

如果这太困难了,请使用特殊的unicode库,例如:http://utfcpp.sourceforge.net/

并学习有关Unicode的知识:http://en.wikipedia.org/wiki/Unicode。在那里,您会找到有关不同Unicode编码的参考资料。


0

即使是UTF-8,你也不能可靠地将Unicode转换为ASCII。字符集(Unicode文档中的“平面”)无法映射回ASCII - 这就是Unicode存在的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接