C++ 中的 Unicode 字符串处理

Posted

技术标签:

【中文标题】C++ 中的 Unicode 字符串处理【英文标题】:Unicode string handling in C++ 【发布时间】:2013-12-02 09:22:50 【问题描述】:

我经历了足够多的线程并发布了关于这个主题的帖子,但不知何故它并没有帮助我在我的代码中添加 unicode 支持。 我有很简单的任务要做 - 读取 Unicode 文件(.txt 和 csv) - 使用一些分隔符(或“分隔的单词”)解析它并将单词作为标记存储在 2D 数组中 - 对其进行一些操作 - 存储这些字符串文本文件

我面临的问题是我的一些旧代码函数不兼容,我猜是因为我找不到替代品,或者我能够编译它们但没有生成输出。 这段代码与 ASCII 配合得很好,但现在我需要 unicode 支持。

如果我得到示例源代码会很棒,不需要是整个大代码,但至少像如何获取 Unicode 文件解析它并将其存储在令牌中以及用于比较的函数等,

我在下面粘贴部分代码,我确实修改了一些东西,所以可能无法在第一次编译。

获取文本文件作为输入,例如profile.txt 是 unicode(UTF 16 - 基本上是中文和韩文)


// adding all std headers here


const int MAX_CHARS_PER_LINE = 4072;  
const int MAX_TOKENS_PER_LINE = 1;      
const wchar_t* const DELIMITER = L"\"";

class IntegrityCheck

    public:
        std::wstring Profile_Container[5000][4];
        void Profile_PRD_Parser();
;

 void IntegrityCheck::Profile_PRD_Parser()


std::wstring skip (L".exe");
std::wstring databoxtemp[1][1];
int a=-1;

// create a file-reading object
wifstream fin.open("profiles.txt");  //open a file
wofstream fout("out.txt");  // this dumps the parsing ouput 

// read each line of the file
while (!fin.eof())

    // read an entire line into memory
    wchar_t buf[MAX_CHARS_PER_LINE];

    fin.getline(buf, MAX_CHARS_PER_LINE);

    // parse the line into blank-delimited tokens
    int n = 0; // a for-loop index

    // array to store memory addresses of the tokens in buf
    const wchar_t* token[MAX_TOKENS_PER_LINE] = ; // initialize to 0

    // parse the line
    token[0] = wcstok(buf, DELIMITER); // first token

    if (token[0]) // zero if line is blank
    

        for (n = 0; n < MAX_TOKENS_PER_LINE; n++)   // setting n=0 as we want to ignore the first token
        
            oken[n] = wcstok(0, DELIMITER); // subsequent tokens

            if (!token[n]) break; // no more tokens

            std::wstring str2 =token[n];

            std::size_t found = str2.find(str);  //substring comparison

            if (found!=std::string::npos)   // if its exe then it writes in Dxout for same app name on new line
            
                a++;
                Profile_Container[a][0]=token[n];
                std::transform(Profile_Container[a][2].begin(), Profile_Container[a][2].end(), Profile_Container[a][2].begin(), ::tolower);  //convert all data to lower 

                fout<<Profile_Container[a][0]<<"\t"<<Profile_Container[a][1]<<"\t"<<Profile_Container[a][2]<<"\n"; //write to file
            

        
    



fout.close();
fin.close();


int main()

IntegrityCheck p1;
p1.Profile_PRD_Parser();
     

【问题讨论】:

有一个错字,这个词拼写为“Integrity”,而不是“Intigrity”。 如果您已经使用using namespace std;,那么没有理由也使用std::cout; 等等来编写。您已经在使用整个 std 命名空间。 只需删除using namespace std 行。它不会“添加所有标准头”。如果您知道它的作用,我不建议您使用它,但是该评论表明您不知道它的作用,因此我必须提出更强烈的建议,不要使用它。 第一件事是删除每一个提及char。调用 getline 时不要转换为 char,使用 wcstok 而不是 strtok。 "现在我需要 unicode 支持。"不是一个很好的问题描述。你想对数据做什么?您希望如何对输入进行编码?这是什么平台? (wsomething 不会神奇地让东西“支持 Unicode”) 【参考方案1】:

快速查看您的代码,我看到的唯一变化是

const wchar_t* const DELIMITER = L"\"";

fin.getline(buf, MAX_CHARS_PER_LINE);

token[0] = wcstok(buf, DELIMITER);

std::transform(Profile_Container[a][2].begin(), Profile_Container[a][2].end(), Profile_Container[a][2].begin(), ::towlower); 

不确定towlower 是否能够将每个 Unicode 字符转换为小写,但如果您的文本是中文和韩文,我想这不是什么大问题。

编辑

在装有 Visual Studio 2010 的 Windows 上需要以下内容

#include <codecvt>
#include <locale>

wifstream fin("profiles.txt", ios_base::binary);  //open a file
fin.imbue(std::locale(fin.getloc(),
   new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));

这对我来说适用于以 UTF-16“大端”(但不是小端)编码的文件。

您当前代码的唯一问题是文件读取(也许是我没有看过的写入)。一旦您可以将文件中的字符转换为字符串,就应该没问题了。

如果上述方法对您不起作用,那么我不确定。这个page 有血淋淋的细节。

【讨论】:

,谢谢约翰更具体,我会做出改变,看看它是怎么回事并更新到线程 我在代码中进行了更正,它的编译但我遗漏了一些东西,基本上 getline 从 unicode 文件中获取该行,然后我尝试将其分解为标记(使用分隔符)但我看到 getline 得到二进制和henc中的所有内容都无法将缓冲区分解为令牌,并且比较失败并且我得到空白输出,然后我需要将其转换回ASCII吗?但它会丢失数据吗?那么我应该如何处理呢?我写的所有逻辑都牢记简单的 ASCII 字符串,现在它变得困难了。任何使它工作的建议都非常受欢迎 或者您是否建议其他方法来执行此操作?我搜索但找不到有关 unicode 文本文件解析的相关文章或示例代码 我现在真的被这个 unicode 卡住了,有人可以帮我吗? @NeileshC 我试过你的代码,很惊讶它不起作用(对我来说)。问题是仅使用 wchar_t 不足以告诉编译器您的文件是 UTF-16。似乎没有任何完全独立于平台的方式来执行此操作,因此继续进行的方式取决于您的编译器等。我已经用一些对我有用的代码更新了上面的答案。【参考方案2】:

编译并运行的最终代码:

fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff,std::codecvt_mode(std::little_endian|std::consume_header)>));
fout.imbue(std::locale(fin.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff,std::codecvt_mode(std::little_endian|std::consume_header)>));


while (!fin.eof())


 wchar_t buf[MAX_CHARS_PER_LINE];

 fin.getline(buf, MAX_CHARS_PER_LINE);

 wchar_t* token[MAX_TOKENS_PER_LINE] = ;
token[0] = wcstok(buf, DELIMITER);


if (token[0]) // zero if line is blank

    int n = 0; 
    for (n = 0; n < MAX_TOKENS_PER_LINE; n++)   // setting n=0 as we want to ignore the first token
    
        token[n] = wcstok(0, DELIMITER); // subsequent tokens


        if (!token[n]) break; // no more tokens

        std::wstring str2 =token[n];

        std::size_t found = str2.find(str);  //substring comparison

        if (found!=std::string::npos)   // if its exe then it writes in Dxout for same app name on new line
          
            a++;
            Profile_Container[a][0]=token[n];
            fout<<Profile_Container[a][0];
        
    

【讨论】:

以上是关于C++ 中的 Unicode 字符串处理的主要内容,如果未能解决你的问题,请参考以下文章

通过 Windows 批处理文件将字符串替换为文本文件中的 unicode

Visual C++:将传统 C 和 C++ 字符串代码迁移到 Unicode 世界

如何在 python 包装中使用 unicode 字符串用于带有 cython 的 c++ 类?

Python2 处理 Unicode 字符串的规则

HTMLCSSJS对unicode字符的不同处理

TCHAR