在C中计算土耳其字符

时间:2016-12-28 00:24:26

标签: c count character-encoding

我正在尝试编写一个程序来计算土耳其语字符串中的所有字符。我不明白为什么这不起作用。我添加了库,setlocale(LC_ALL,“土耳其语”),但仍然无效。谢谢。这是我的代码: 我的文件字符编码: utf_8

int main(){

    setlocale(LC_ALL,"turkish");
    char string[9000];
    int c = 0, count[30] = {0};
    int bahar = 0;    

    ...
        if ( string[c] >= 'a' && string[c] <= 'z' ){
            count[string[c]-'a']++;
            bahar++;

}

我的输出:

0.085217 b 0.015272 c 0.022602 d 0.035736 e 0.110263 f 0.029933 g 0.015272 h 0.053146 我0.071167 k 0.010996 l 0.047954 m 0.025046 n 0.095907 o 0.069334 p 0.013745 q 0.002443 r 0.053451 s 0.073916 t 0.095296 你0.036958 v 0.004582 w 0.019243 x 0.001527 是0.010996

这是英文字母,但我也需要这个字符计算:“ğ,ü,ç,ı,ö”

3 个答案:

答案 0 :(得分:2)

setlocale(LC_ALL,"turkish");

首先:"turkish"不是区域设置。

区域设置的正确名称通常类似于xx_YY.CHARSET,其中xx是该语言的ISO 639-1代码,YYISO 3166-1 Alpha-2 code国家/地区CHARSET是可选的字符集名称(通常为ISO8859-1ISO8859-15UTF-8)。请注意,并非所有组合都有效;计算机必须具有为语言代码,国家/地区代码和字符集的特定组合生成的区域设置文件。

您可能需要的是setlocale(LC_ALL, "tr_TR.UTF-8")

if ( string[c] >= 'a' && string[c] <= 'z' ){

第二:>=<=等比较运算符不区分区域设置。此比较将始终对字节执行,并且不包括ASCII a - z范围之外的字符。

要执行区分区域敏感的比较,您必须使用strcoll()之类的函数。但是,请注意,有些字母(包括您在此处尝试包含的字母!)由UTF-8中的多字节序列组成,因此循环字节也不会起作用。您需要使用mblen()mbtowc()等函数来分隔这些序列。

答案 1 :(得分:2)

由于您显然使用的是UTF-8文件,答案取决于您的执行平台:

  1. 如果您使用的是Linux,那么setlocale(LC_CTYPE, "en_US.UTF-8")或类似内容应该可以正常运行,但最重要的部分是UTF-8!语言无关紧要。您可以使用

    验证它是否有效
    if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) {
        abort();
    }
    

    这将阻止程序执行。该代码之后的任何内容都意味着语言环境设置正确。

  2. 如果您使用的是Windows,则可以使用fopen("myfile.txt", "rt, ccs=UTF-8")打开该文件。但是,这并非完全可移植到其他平台。然而,它比替代品更清洁,在这种特殊情况下可能更为重要。

  3. 如果您正在使用FreeBSD或其他不允许您使用这两种方法的系统(例如,没有UTF-8语言环境),您需要手动解析字节或使用库为你转换它们。如果您的实现具有iconv()函数,则可以使用它将UTF-8转换为ISO-8859-9,以将特殊字符用作单个字节。

  4. 准备好阅读文件后,您可以将fgetwswchar_t数组一起使用。

    另一个问题是检查是否检测到您的某个非ASCII字符。你可以这样做:

    // lower = "abcdefghijklmnopqrstuvwxyzçöüğı"
    // upper = "ABCDEFGHİJKLMNOPQRSTUVWXYZÇÖÜĞI"
    const wchar_t lower[] = L"abcdefghijklmnopqrstuvwxyz\u00E7\u00F6\u00FC\u011F\u0131";
    const wchar_t upper[] = L"ABCDEFGH\u0130JKLMNOPQRSTUVWXYZ\u00C7\u00D6\u00DC\u011EI";
    
    const wchar_t *lchptr = wcschr(lower, string[c]);
    const wchar_t *uchptr = wcschr(upper, string[c]);
    if (lchptr) {
        count[(size_t)(lchptr-lower)]++;
        bahar++;
    } else if (uchptr) {
        count[(size_t)(uchptr-upper)]++;
        bahar++;
    }
    

    该代码假定您在不考虑大小写的情况下对字符进行计数(不区分大小写)。也就是说,ı\u0131)和I被视为相同的字符(count[8]++),就像İ\u0130)和{ {1}}被视为相同(i)。我不会声称对土耳其语有太多了解,但是当我创建大写和小写字符串时,我使用了我对土耳其套管规则的了解。

    修改

    正如@JonathanLeffler在问题评论中提到的,更好的解决方案是在count[29]++中的每个字符上使用isalpha(或者在这种情况下,iswalpha)而不是我使用的stringlower个有效字符串。但是,这只会让您知道该字符是一个字母字符;它不会告诉你要使用的upper数组的索引,事实是没有通用的答案,因为有些语言只使用带变音符号的几个字符而不是整个组可以做count。换句话说,即使您已经读取了数据,您仍然需要将其转换为适合您的解决方案,并且需要了解您正在使用的内容来创建从字符到整数值的映射,我的代码通过使用字符串中的有效字符串和每个字符的索引作为string[c] >= L'à' && string[c] <= L'ç'数组的索引(即count将表示lower[29]将被执行,count[29]++将表示{执行{1}}。

答案 2 :(得分:0)

解决方案取决于文件的字符编码。

如果文件是ISO 8859-9(latin-5),那么每个特殊字符仍然只能在一个字节中编码,您可以轻松修改代码:您已经在大写和小写之间存在分歧。只需为特殊字符添加更多分支。

如果文件是UTF-8或其他一些unicode编码,则需要一个支持多字节的字符串库。