我有一个类似的问题,询问哪种语言最适合这项任务,而Perl就是答案。但我仍然很好奇如何用C解决这个问题。
我想给这个程序一个大文本文件,里面装满了从小说,报纸,网页上摘取的德文文本样本。我想要一个文本文件中所有单词的频率列表,按最常见的单词排序。我需要列出3000个最常见的德语单词。
如果这只是一个ASCII问题,那么这对我来说就是孩子的游戏。在整个早上读完Unicode之后,我真的很惊讶雷区是什么。
这是如何在C中完成的?
我有一个朋友在Python中放了一些东西,但他仍然是初学者,他的代码在1.4 MB文本文件上花了大约30分钟。
答案 0 :(得分:5)
这取决于编码。最简单的是UTF-8,您可以在char*
数组中简单地存储字符串。令人惊讶的是,构建频率列表将使用几乎相同的代码完成,就像ASCII文本一样。这是一种UTF-8魔术,但这就是为什么这种编码如此强大!
在这种情况下,你应该记住一些事情:
Unicode提供比ASCII更多的白色字符。您需要一个列表来了解单词的分隔位置。很高兴,Wikipedia has one。
Unicode并不总是毫不含糊。有些情况下,不同的序列产生相同的字符。通常使用组合字符:例如:德语Ä
可以表示为:
U+00C4
- 单个字母Ä
U+0041 U+0308
- 拉丁字母A
和分音符(umlaut)。令人高兴的是,在德语中只有七个非英语字符:ÄäÖöÜüß
。您需要检查其替代变体的外观(例如,在第4页和第5页here,您应该找到所有德语字符及其替代形式)。
当然,要解决这两个问题,您还需要了解所有结果如何用UTF-8表示。这在RFC 3629,第3页中有所描述。
如果是其他编码(或其他语言),我建议不要自己处理,而是使用一些现有的库。如果您使用的是Linux(或大多数其他Unices),则可以使用iconv
函数(man 3 iconv
)将文本转换为UTF-8,然后按照我之前的描述进行操作。
其他选择是使用一些已经处理各种Unicode变体的库。最强大的可能是ICU - International Components For Unicode,请查看他们的手册以了解如何使用它来执行任务。
答案 1 :(得分:1)
您尚未明确规定您的计划要求,但我只能想到您可能需要关注角色身份的两个方面:
如果输入文本是大小写混合的情况,您可能希望将所有单词映射到同一个案例,以便同一个单词的不同用途版本一起计算。
如果输入采用混合标准化形式(某些字符预先组合,其他字符已经分解),那么您需要执行标准化以确保仅以这种方式不同的单词一起计算。
例如,如果您的输入是全小写的NFC,那么用ASCII编写的程序将非常适合您的任务。由于情况可能并非如此,因此您需要评估您的要求。对于问题1(案例),您可以使用宽字符stdio函数(或面向字节的stdio和mbsrtowcs
)和towlower
来进行大小写映射。对于问题2(规范化),您需要为C使用现有的Unicode库,或者自己动手。
答案 2 :(得分:0)
您可以使用wchar_t
字符串以及wchar.h
头文件中定义的函数。
答案 3 :(得分:0)
如果你能在没有ASCII问题的情况下做到这一点,那么在Unicode中应该不会那么难(至少在C99中)。
几乎所有处理字符串和字符的标准库函数都具有广泛的字符等价,当你使用宽字符时,你永远不必担心底层编码 - 一个宽字符代表一个实际字符。有iswupper
,towupper
,wcslen
等等。
假设您在一个简单的环境中工作(例如UTF-8系统,UTF-8文本),因为语言环境将处理所有事情。如果没有,还有更多的工作。
答案 4 :(得分:0)
您可能希望使用系统工具来解决此问题,如果您的系统区域设置正确,则可以执行此操作。 AWK是一个你可以很容易使用的,例如:
BEGIN {
FS="[^[:alpha:]]"
}
{
for(i=1; i<=NF; i++) {
if(array[$i]) {
array[$i] += 1
} else {
array[$i] = 1
}
}
}
END{
for(i in array) {printf "%s = %d\n", i, array[i] }
}
调用:
$ awk -f script.awk German.txt | sort
编辑:
这是非常关闭你正在寻找的东西。