【问题标题】:Counting Turkish character in C在C中计算土耳其字符
【发布时间】:2017-05-12 06:03:32
【问题描述】:

我正在尝试编写一个程序,以土耳其语计算字符串中的所有字符。我不明白为什么这不起作用。我添加了库 setlocale(LC_ALL,"turkish") 但仍然无法正常工作。谢谢你。这是我的代码: 我的文件字符编码: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 米 0.025046 n 0.095907 Ø 0.069334 p 0.013745 q 0.002443 r 0.053451 0.073916 吨 0.095296 你 0.036958 v 0.004582 w 0.019243 x 0.001527 是 0.010996

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

【问题讨论】:

  • 您需要一个处理 UTF8/UTF16/UTF32 的 unicode 库。
  • ...并检查您是否可以打开文件
  • 那我该如何解决? @stargateur
  • 你检查并打印了setlocale()的返回值吗? "turkish" 是有效的语言环境字符串吗? (我默认使用en_US.UTF-8:我希望您使用诸如tr_TR.UTF-8tr-TR.ISO8859-9 或类似的代码——这两个语言环境都存在于macOS Sierra,至少在我的机器上。)跨度>
  • en_US.UTF-8 字符串用于美国英语; en_GB.UTF-8 英式英语;两者都使用 UTF-8 代码集。请注意,您使用 if (string[c] &gt;= 'a' &amp;&amp; string[c] &lt;= 'z') 的测试仅检测基本 ASCII(小写)范围内的非重音字母。您需要使用&lt;ctype.h&gt; 中的isalpha() 来检测基本ASCII 范围之外的字母字符。然后,您必须将它们映射到适当的索引以正确计算它们。这是 Chrono Kitsune 对他们的回答所做的一些事情。与这样的角色打交道是一项艰巨的工作。了解代码集(您发现的是 UTF-8)至关重要。

标签: c count character-encoding


【解决方案1】:

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

如果文件采用 ISO 8859-9 (latin-5) 格式,则每个特殊字符仍以单个字节编码,您可以轻松修改代码:您已经区分大小写。只需为特殊字符添加更多分支。

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

【讨论】:

  • 所以我添加了这个 #include &lt;wchar.h&gt; wchar_t string[9000]; 并且我收到了错误这一行:if ( fgets(string, 9000, plain) != NULL) { puts(string); 仍然不起作用。
  • 你的文件的字符编码是什么?
  • setlocale(LC_ALL,"turkish");@LudwigSchulze
  • 绝对不是! “file plaintext.txt”的输出是什么
  • 不可能!我不是在询问文件的内容,而是询问它的字符编码。阅读en.wikipedia.org/wiki/ISO/IEC_8859-9en.wikipedia.org/wiki/UTF-8,了解您的问题领域!
【解决方案2】:
setlocale(LC_ALL,"turkish");

首先:"turkish" 不是语言环境。

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

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


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

第二:比较运算符如&gt;=&lt;= 不区分区域设置。此比较将始终在字节上执行,并且不会包括 ASCII a-z 范围之外的字符。

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

【讨论】:

  • 感谢您的回复,我试过这个setlocale(LC_ALL, "tr_TR.UTF-8") 但仍然只计算英文字符。我不明白为什么这不起作用。
  • 谢谢,但这会改变整个代码吗?我不知道这个函数 strcoll() 和其他函数是如何工作的,我会搜索它。谢谢。
  • 是的,您必须对程序进行相当大的更改才能支持 UTF-8 文本。
【解决方案3】:

由于您显然使用的是 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 以将您的特殊字符用作单个字节。

准备好读取文件后,您可以使用 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) 和 i 被认为是同一个字符 (count[29]++)。我不会声称对土耳其语了解很多,但在创建大写和小写字符串时,我使用了我对土耳其语大小写规则了解的一点点。

编辑

正如@JonathanLeffler 在问题的 cmets 中提到的那样,更好的解决方案是在string 中的每个字符上使用isalpha(或在本例中为iswalpha),而不是lower 和@987654342 @ 我使用的有效字符的字符串。但是,这只会让您知道该字符是字母字符;它不会告诉您要使用的 count 数组的索引,事实是没有通用的答案,因为有些语言只使用带有变音符号的几个字符而不是整个组做string[c] &gt;= L'à' &amp;&amp; string[c] &lt;= L'ç'。换句话说,即使您已经读取了数据,您仍然需要将其转换为适合您的解决方案,这需要了解您正在使用什么来创建从字符到整数值的映射,我的代码通过使用有效字符的字符串和字符串中每个字符的索引作为count数组的索引(即lower[29]意味着count[29]++被执行,upper[18]意味着count[18]++被执行)。

【讨论】:

  • 谢谢,我在 Linux (Mac OS X) 上使用 Xcode。首先我添加了这一行 wchar_t string[9000];if ( fgetws(string, 9000, plain) != NULL) { fputws(string, plain);} 在这里没问题。我在上面添加了您的代码,但如果我不编写此代码,所有行都会出错:if (setlocale(LC_CTYPE, "en_US.UTF-8")) != NULL) { abort();} 错误是:预期的表达式。如果我删除它然后我得到错误:count[chptr-1]++; *Array 下标不是整数。 ** 我也收到了这行错误:chptr -= (lower-1); incompatible integer to pointer conversion const wchar_t (aka const int*)from long
  • @jekyll 我修改了我的答案。 setlocale 行有一个额外的右括号,我希望修复你提到的所有其他内容。
  • 谢谢,实际上我找到了另一种方法,但这次我的输出是八进制 :D \347 0.006665 :D :))) \347 是ç。
  • 谢谢你我明白了。我想知道如何数两个字母?二元组。我的意思是,bigram 计数计算字符对的频率。
  • @jekyll 这应该是一个新问题,但在提问之前尝试寻找答案。可能有人已经问过类似的问题了。
猜你喜欢
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多