c ++为什么ifstream get()函数返回无法识别的特殊字符?

时间:2018-08-04 18:06:50

标签: c++ string file vector locale

我正在尝试在c ++中实现Text类,该类加载文本文件(.txt),搜索该文件中的每个字符并存储所有单词和所有定界符(在这种情况下,定界符将是所有一个字符)在两个各自的向量(#include <vector>)中。由于文本文件main包含特殊字符,因此我使用setlocale(LC_ALL, "pt_BR.UTF-8")设置了程序的语言环境。

随着下面代码的执行(作为类文本的构造函数),我注意到在构造ifstream类并且代码进入while循环之后,我进入了char c已使用arch.get(c)存储,其中包含一个无法识别的角色(这个坏男孩在这里:▒)。

在这种情况下,c是特殊字符,如果显示字母(由string d标识),它将保存在字符串(isalpha(c))上并在下一个循环中保存。在文件上,它将string d存储在各自的分隔符矢量上。相同的逻辑适用于字母,因为它们先保存在string p上,然后再保存在单词vector(英语中的 words = palavras )中。我最困惑的部分是当我打印string d并检查其值时,文件中识别出的特殊字符会正确显示。

为什么将特殊字符插入string才能识别特殊字符?为什么arch.get(c)函数返回无法识别的字符?

以下代码是类Text的构造函数。用于测试的打印带有注释以供指示。

Text::Text( string na ) {
    // Inicialization of variables
    total_size = 0;
    word_first_flag = false;
    namearch = na;
    string p = "";
    string d = "";
    vector<string>::iterator it_delim;
    it_palavras = palavras.begin();
    it_delim = delim.begin();

    setlocale(LC_ALL, "pt_BR.UTF-8");

    ifstream arch(namearch);

    char c;

    while(arch.get(c)) {
        if(total_size > 10000)
            break;

            cout << c << endl; // Prints ▒

        switch (isalpha(c)) { // does not recognize special characters
            case 0:
                if(p == "") {
                    d = d + c;
                    cout << "-" << d << "-"<< endl; // Prints correct char
                }
                else {
                    Palavra paux;
                    paux = p;
                    palavras.push_back(paux);
                    p = "";
                    d = d + c;
                }
            break;
            default:
                if(total_size == 0) word_first_flag = true;

                if(d == "") {
                    p = p + c;
                }
                else {
                    delim.push_back(d);
                    cout << "-" << d << "-" << " Inserted!" << endl << endl; // Also prints correct char
                    d = "";
                    p = p + c;
                }
            break;
            }

            ++total_size;
        }
    }

    if(d != "")
        delim.push_back(d);

    it_palavras = palavras.begin();
    arch.close();
}

根据locale类的文档,对于特殊字符,一切都应正常工作。但是事实并非如此。我也尝试过在字符串中插入c,但是它只是保存了错误的字符。根据{{​​3}}

,我可以更改wstringswchat_t的所有类型,但是语言环境设置显然已经做到了
  

在C ++中,语言环境由语言环境类的对象表示。每   这些语言环境对象中包含使用   一系列与文化相关的功能。

我正在Cygwin的gcc 6.4.0版本上进行编译。我也知道我可以使用gdb进行调试,但是在此阶段并没有太大帮助。

1 个答案:

答案 0 :(得分:0)

因此,通过@Igor Tandetnik的非常有用的见解以及对这些类型的数据进行的一些测试,我已经更改了原始代码,以便它可以正确地从存档中提取特殊字符。

Text::Text( string na ) {
// Inicialization of variables
total_size = 0;
word_first_flag = false;
namearch = na;
wstring p = L"";
wstring d = L"";
vector<wstring>::iterator it_delim;
it_palavras = palavras.begin();
it_delim = delim.begin();

setlocale(LC_ALL, "pt_BR.UTF-8");

wifstream arch(namearch);

wchar_t c;

while(arch.get(c)) {
    if(total_size > 10000)
        break;

        wcout << c << endl;

    switch (iswalpha(c)) {
        case 0:
            if(p == L"") {
                d = d + c;
                wcout << "-" << d << "-"<< endl;
            }
            else {
                Palavra paux;
                paux = p;
                palavras.push_back(paux);
                p = L"";
                d = d + c;
            }
        break;
        default:
            if(total_size == 0) word_first_flag = true;

            if(d == L"") {
                p = p + c;
            }
            else {
                delim.push_back(d);
                wcout << "-" << d << "-" << " Inserted!" << endl << endl;
                d = L"";
                p = p + c;
            }
        break;
        }

        ++total_size;
    }
}

if(d != L"")
    delim.push_back(d);

it_palavras = palavras.begin();
arch.close();
}

简而言之,对代码的调整是:

  1. 将所有charstring和iostream更改为其多字节格式(例如:wchar_twstringwcout) ;

  2. 在每个字符或字符串(LL'')前添加L""进行多字节转换。