我写了一个简单的代码来计算文本中不同字符的数量。这是下面的代码:
#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字符工作,如何解决问题呢?
答案 0 :(得分:2)
首先,您想要算什么? Unicode代码点或字形集群,即编码意义上的字符,或读者感知的字符?还要记住&#34;宽字符&#34; (16位字符)不是Unicode字符(UTF-16是可变长度,就像UTF-8!)。
在任何情况下,获取ICU等库以进行实际的代码点/集群迭代。为了计数,您需要使用适当的类型替换char
中的map
类型(代码点为32位unsigned int
,或者为字形集群标准化字符串,应再次进行规范化由图书馆照顾)
Grapheme群集:http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
答案 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];
}
您会注意到大多数代码都涉及错误处理。