如何使用C ++计算文本中Unicode字符的数量

时间:2013-05-20 16:14:41

标签: c++ unicode

我写了一个简单的代码来计算文本中不同字符的数量。这是下面的代码:

#include <iostream>
#include <fstream>
#include <map>
using namespace std;
const char* filename="text.txt";
int main()
{
    map<char,int> dict;
    fstream f(filename);
    char ch;
    while (f.get(ch))
    {
        if(!f.eof())
            cout<<ch;
        if (!dict[ch])
            dict[ch]=0;
        dict[ch]++;
    }
    f.close();
    cout<<endl;
    for (auto it=dict.begin();it!=dict.end();it++)
    {
        cout<<(*it).first<<":\t"<<(*it).second<<endl;
    }
    system("pause");
}

该程序在计算ascii字符方面做得很好,但它不能像汉字那样在Unicode字符中工作。如果我希望它能够以Unicode字符工作,如何解决问题呢?

4 个答案:

答案 0 :(得分:2)

首先,您想要算什么? Unicode代码点或字形集群,即编码意义上的字符,或读者感知的字符?还要记住&#34;宽字符&#34; (16位字符)不是Unicode字符(UTF-16是可变长度,就像UTF-8!)。

在任何情况下,获取ICU等库以进行实际的代码点/集群迭代。为了计数,您需要使用适当的类型替换char中的map类型(代码点为32位unsigned int,或者为字形集群标准化字符串,应再次进行规范化由图书馆照顾)

ICU:http://icu-project.org

Grapheme群集:http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries

规范化:http://unicode.org/reports/tr15/

答案 1 :(得分:1)

您需要一个Unicode库来处理Unicode字符。编码 - 比方说 - UTF8本身就是一项艰巨的任务,并重新发明轮子。

this Q/A from SO中提到了一个很好的,你可以从其他答案中找到建议。

答案 2 :(得分:0)

所有内容都有广泛的char版本,但是如果你想做一些与你现在拥有的非常类似的东西并使用16位版本的unicode:

map<short,int> dict;
fstream f(filename);
char ch;
short val;
while (1)
{
    // Beware endian issues here - should work either way for char counting though.
    f.get(ch);
    val = ch;
    f.get(ch);
    val |= ch << 8;

    if(val == 0) break;

    if(!f.eof())
        cout<<val;
    if (!dict[val])
        dict[val]=0;
    dict[val]++;
}
f.close();
cout<<endl;
for (auto it=dict.begin();it!=dict.end();it++)
{
    cout<<(*it).first<<":\t"<<(*it).second<<endl;
}

上面的代码做了很多假设(所有字符都是16位,甚至是文件中的字节数等),但它应该做你想要的,或者至少让你快速了解它如何工作宽字符。

答案 3 :(得分:0)

如果您可以妥协并只计算代码点,那就相当了 简单易用UTF-8直接做。但是,你的字典会 必须是std::map<std::string, int>。一旦你有了 UTF-8的第一个字符:

while ( f.get( ch ) ) {
    static size_t const charLen[] = 
    {
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
          2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
          2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
          3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
          4,  4,  4,  4,  4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  0,  0,
    } ;
    int chLen = charLen[ static_cast<unsigned char>( ch ) ];
    if ( chLen <= 0 ) {
        //  error: impossible first character for UTF-8
    }
    std::string codepoint( 1, ch );
    -- chLen;
    while ( chLen != 0 ) {
        if ( !f.get( ch ) ) {
            //  error: file ends in middle of a UTF-8 code point.
        } else if ( (ch & 0xC0) != 0x80 ) {
            //  error: illegal following character in UTF-8
        } else {
            codepoint += ch;
        }
    }
    ++ dict[codepoint];
}

您会注意到大多数代码都涉及错误处理。