1

我有一个类似的问题,询问哪种语言最适合这项任务,Perl 就是答案。但我仍然很好奇如何用 C 解决这个问题。

我想给这个程序一个大的文本文件,里面装满了从小说、报纸、网页中提取的德语文本样本。我想要一个文本文件中所有单词的频率列表,按最常见的单词排序。我需要 3000 个最常见的德语单词列表。

如果这只是一个 ASCII 问题,那么这对我来说就是小菜一碟。整个上午都在阅读有关 Unicode 的内容后,我真的很惊讶它是一个雷区。

这是如何在 C 中完成的?

我有一个朋友用 Python 编写了一些东西,但他还是个初学者,他的代码在一个 1.4 MB 的文本文件上花了大约 30 分钟。

4

5 回答 5

5

这取决于编码。最简单的一种是 UTF-8,您可以在其中简单地将字符串存储在char*数组中。令人惊讶的是,构建频率列表将使用与 ASCII 文本几乎相同的代码来完成。这是一种 UTF-8 魔法,但这就是为什么这种编码如此强大的原因!

在这种情况下,您应该记住以下几点:

  1. Unicode 提供比 ASCII 更多的白色字符。您需要一份它们的列表才能知道单词的分隔位置。令人高兴的是,维基百科有一个.

  2. Unicode 并不总是明确的。在某些情况下,不同的序列会产生相同的字符。它通常发生在组合字符中:例如德语Ä可以表示为:

    • 字符U+00C4- 单个字母Ä
    • 序列U+0041 U+0308- 拉丁字母A和分音符(变音符号)。

令人高兴的是,在德语中只有七个非英文字符:ÄäÖöÜüß. 您需要检查它们的替代变体的外观(例如在第 4 页和第 5 页,您应该找到所有德语字符及其替代形式)。

当然,要解决这两个问题,您还需要知道您的所有发现如何在 UTF-8 中表示。这在RFC 3629第 3 页中进行了描述。

如果是其他编码(或其他语言),我建议不要自己处理,而是使用一些已经存在的库。如果您使用的是 Linux(或大多数其他 Unices),您可以使用iconv函数 ( man 3 iconv) 将您的文本转换为 UTF-8,然后按照我之前的描述进行操作。

其他选择是使用一些已经处理各种 Unicode 变体的库。最强大的可能是ICU - International Components For Unicode,查看他们的手册以了解如何使用它来执行您的任务。

于 2013-03-31T22:30:07.523 回答
1

您没有明确说明您的程序的要求,但我只能想到两个方面可能需要您关心角色身份:

  1. 如果输入文本是大小写混合的,您可能希望将所有单词映射到相同大小写,以便将同一单词的不同大小写版本一起计算。

  2. 如果输入是混合规范化形式(一些字符预先组合,其他字符分解),那么您需要执行规范化以确保仅以这种方式不同的单词被计算在一起。

例如,如果您的输入是全小写的 NFC,那么只考虑 ASCII 编写的程序将非常适合您的任务。由于情况可能并非如此,因此您需要评估您的要求。对于问题 1(案例),您可能可以使用宽字符 stdio 函数(或面向字节的 stdio 和mbsrtowcs)并towlower进行案例映射。对于问题 2(规范化),您需要使用现有的 C Unicode 库或滚动您自己的库。

于 2013-03-31T22:53:28.110 回答
0

您可以使用头文件中wchar_t定义的字符串和函数。wchar.h

于 2013-03-31T21:54:12.520 回答
0

如果您可以在 ASCII 中毫无问题地做到这一点,那么在 Unicode 中应该不会更难(至少在 C99 中)。

几乎所有适用于字符串和字符的标准库函数都具有等价的宽字符,当您使用宽字符时,您永远不必担心底层编码 - 一个宽字符代表一个实际字符。有iswuppertowupperwcslen

这是假设您在一个简单的环境中工作(例如 UTF-8 系统、UTF-8 文本),因为语言环境将处理所有事情。如果没有,还有更多的工作。

于 2013-03-31T22:23:46.350 回答
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

编辑:

这与您正在寻找的非常接近。

于 2013-04-01T00:46:30.250 回答