【问题标题】:Reading Unicode characters from a file in C++从 C++ 文件中读取 Unicode 字符
【发布时间】:2012-02-04 17:06:40
【问题描述】:

我想逐个字符地读取 Unicode 文件 (UTF-8),但我不知道如何逐个字符地读取文件。

谁能告诉我怎么做?

【问题讨论】:

  • 您想读取单个 Unicode 字符或 utf-8 字节?
  • 读取文件,然后将 UTF-8 转换为 UTF-32。您可以使用iconv()、libicu 或 C++11。
  • @Kerrek SB C++11 包含这个吗?我们应该寻找什么类或函数?
  • @WTP:它应该在<cuchar>,它实际上来自C99 支持。肯定有 UTF16 UTF32 支持;我现在不能 100% 确定是否还支持 UTF8。
  • C++11 确实支持 UTF-8。 codecvt<char32_t,char,mbstate_t> 在 UTF-8 和 UTF-32 之间转换。您可以将它与wstring_convert 一起使用,如下所示:wstring_convert<codecvt<char32_t,char,mbstate_t>,char32_t> convert; u32string s = convert.from_bytes("foo");

标签: c++ windows unicode utf-8


【解决方案1】:

首先看一下UTF-8是如何编码字符的:http://en.wikipedia.org/wiki/UTF-8#Description

每个 Unicode 字符都被编码为一个或多个 UTF-8 字节。在您读取文件中的第一个下一个字节后,根据该表:

(第 1 行)如果最高有效位为 0 (char & 0x80 == 0),则您有自己的角色。

(第 2 行)如果三个最高有效位是 110(char & 0xE0 == 0xc0),则必须读取另一个字节,第一个 UTF-8 字节(110YYYyy)的位 4,3,2 成为第一个字节Unicode 字符 (00000YYY) 和下一个字节的 6 个最低有效位 (10xxxxxx) 的两个最低有效位组成 Unicode 字符的第二个字节 (yyxxxxxx);您可以轻松地使用 C/C++ 的移位和逻辑运算符进行位运算:

UnicodeByte1 =   (UTF8Byte1 << 3) & 0xE0;
UnicodeByte2 = ( (UTF8Byte1 << 6) & 0xC0 ) | (UTF8Byte2 & 0x3F);

等等……

听起来有点复杂,但如果您知道如何修改这些位以将它们放置在适当的位置以解码 UTF-8 字符串,这并不难。

【讨论】:

  • 更进一步,UTF-8 字节序列中的第一个字节告诉您该序列中有多少额外的字节。
【解决方案2】:

UTF-8 与 ASCII 兼容,因此您可以像读取 ASCII 文件一样读取 UTF-8 文件。将整个文件读入字符串的 C++ 方法是:

#include <iostream>
#include <string>
#include <fstream>

std::ifstream fs("my_file.txt");
std::string content((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());

生成的字符串具有对应于 UTF-8 字节的字符。你可以像这样循环遍历它:

for (std::string::iterator i = content.begin(); i != content.end(); ++i) {
    char nextChar = *i;
    // do stuff here.
}

或者,您可以以二进制模式打开文件,然后以这种方式遍历每个字节:

std::ifstream fs("my_file.txt", std::ifstream::binary);
if (fs.is_open()) {
    char nextChar;
    while (fs.good()) {
        fs >> nextChar;
        // do stuff here.
    }
}

如果你想做更复杂的事情,我建议你看看Qt。我发现它对这类东西非常有用。至少,不像ICU 那样痛苦,因为做了很多实际的事情。

QFile file;
if (file.open("my_file.text") {
    QTextStream in(&file);
    in.setCodec("UTF-8")
    QString contents = in.readAll();

    return;
}

【讨论】:

  • 您的解决方案不输出字母,而是输出字节。这仅适用于 utf-8 字符集的 ASCII 部分。
  • @JindraHelcl 我的解决方案不输出任何内容:它读取一个文件并使该文件中的数据可用于进一步处理。提问者从未指定他是想读取文件中的字节(我的解决方案回答)还是读取文件中的字符(我已经展示了如何使用 Qt)。请记住,这个答案是 3 岁。
【解决方案3】:

理论上 strlib.h 有一个函数 mblen,它的 shell 返回多字节符号的长度。但在我的情况下,它为多字节符号的第一个字节返回 -1 并继续它一直返回。所以我写了以下内容:

{
    if(i_ch == nullptr) return -1;
    int l = 0;
    char ch = *i_ch;
    int mask = 0x80;
    while(ch & mask) {
        l++;
        mask = (mask >> 1);
    }
    if (l < 4) return -1;
    return l;
}  

这比研究shell如何使用mblen花费的时间更少。

【讨论】:

    【解决方案4】:

    试试这个:获取文件,然后根据它的长度循环遍历文本

    伪代码:

    String s = file.toString();
    int len = s.length();
    for(int i=0; i < len; i++)
    {
        String the_character = s[i].
    
        // TODO : Do your thing :o)
    }
    

    【讨论】:

    • 这不适用于 UTF-8 字符串(假设 String 是 std::string)。
    • C++ 中没有“file.toString()”。
    猜你喜欢
    • 2019-03-18
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 2016-10-16
    • 2011-01-19
    • 1970-01-01
    相关资源
    最近更新 更多