2016-12-28 1 views
1

Я пытаюсь написать программу, которая учитывает все символы в строке на турецком языке. Я не понимаю, почему это не работает. я добавил библиотеку, setlocale (LC_ALL, «turkish»), но все равно не работает. Спасибо. Вот мой код: Моей файл кодировка: UTF_8Подсчет турецкого символа в C

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 б 0,015272 с 0,022602 d 0,035736 х 0,110263 х 0,029933 г 0,015272 ч 0.053146 i 0.071167 k 0,010996 l 0.047954 m 0.025046 п 0,095907 о 0,069334 р 0,013745 д 0,002443 г 0,053451 сек 0,073916 т 0,095296 у 0,036958 против 0,004582 ш 0,019243 х 0,001527 у 0.010996

Это английский алфавит, но мне нужно это символы расчет тоже: «ü, ü, ç, ı, ö»

+0

Вам нужна библиотека юникода, которая обрабатывает UTF8/UTF16/UTF32. – Stargateur

+1

... И проверьте, что вы можете открыть файл –

+0

Как я могу это исправить? @stargateur – jekyll

ответ

0

Решение зависит от кодировки символов ваших файлов.

Если файл находится в ISO 8859-9 (latin-5), то каждый специальный символ по-прежнему кодируется в один байт, и вы можете легко изменить свой код: у вас уже есть разница между верхним регистром и нижним регистром , Просто добавьте больше ветвей для специальных символов.

Если файл находится в UTF-8 или какой-либо другой кодировке Unicode, вам нужна многобайтовая библиотека строк.

+0

поэтому я добавил эту '#include ' 'wchar_t string [9000];' и ii получил ошибку в этой строке: 'if (fgets (string, 9000, plain)! = NULL) { puts (string);' still doesn Не работай. – jekyll

+0

А что такое кодировка символов вашего файла? –

+0

'setlocale (LC_ALL,« turkish »);' @LudwigSchulze – jekyll

2
setlocale(LC_ALL,"turkish"); 

Первый: "turkish" - не язык.

Правильное название местности, как правило, выглядят как xx_YY.CHARSET, где xx является ISO 639-1 код языка, YY является ISO 3166-1 Alpha-2 code для страны, и CHARSET необязательный набор символов имя (обычно ISO8859-1, ISO8859-15 или UTF-8). Обратите внимание, что не все комбинации действительны; компьютер должен иметь файлы локали, созданные для этой конкретной комбинации языкового кода, кода страны и набора символов.

Возможно, вы захотите здесь setlocale(LC_ALL, "tr_TR.UTF-8").


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

Второе: Операторы сравнения, как >= и <= не зависит от локали. Это сравнение всегда будет выполняться по байтам и не будет включать символы вне диапазона ASCII a - z.

Чтобы выполнить сравнение, зависящее от локали, вы должны использовать функцию типа strcoll(). Однако обратите внимание на то, что некоторые буквы (включая те, которые вы пытаетесь включить сюда!) Состоят из многобайтовых последовательностей в UTF-8, поэтому цикл с байтами также не будет работать.Для разделения этих последовательностей вам нужно будет использовать функцию, такую ​​как mblen() или mbtowc().

+0

Спасибо за ответ, я попробовал этот 'setlocale (LC_ALL," tr_TR.UTF-8 ")', но все равно вычисляет только английские символы. Я не понимаю, почему это не работает. – jekyll

+0

спасибо, но это изменит весь код? Я не знаю, как это работает с функциями strcoll() и другими, я буду искать его. Благодарю. – jekyll

+0

Да, вам нужно будет существенно изменить свою программу, чтобы поддерживать текст UTF-8. – duskwuff

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, чтобы использовать специальные символы в виде одиночных байтов.

После того, как вы будете готовы, чтобы прочитать файл, вы можете использовать fgetws с wchar_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 упоминалось в комментариях на вопрос, в лучшим решением было бы использовать что-то вроде isalpha (или в данном случае, iswalpha) на каждый символ в string вместо из lower и upper строк действительных символов, которые я использовал. Это, однако, только позволит вам знать, что персонаж является буквенным символом; он не сообщил вам индекс вашего массива count, и на самом деле нет универсального ответа, потому что некоторые языки используют только несколько символов с диакритическими метками, а не целую группу, где вы можете просто сделать string[c] >= L'à' && string[c] <= L'ç' , Другими словами, даже когда вы читаете данные, вам все равно нужно преобразовать их в соответствии с вашим решением, и для этого требуется знание того, с чем вы работаете, для создания сопоставления от символов до целочисленных значений, которые мой код делает с помощью строки действительных символов и индексы каждого символа в строке в качестве индексов массива count (т. е.lower[29] будет иметь значение count[29]++, а upper[18] будет означать, что count[18]++ выполнено).

+0

спасибо, я на 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] ++;' ** Индекс массива не является целым числом. ** и я тоже получил ошибку: 'chptr - = (lower-1);' несовместимое целое число для преобразования указателя const wchar_t * (aka const int *) из long – jekyll

+0

@jekyll Я поправьте свой ответ. Линия 'setlocale' имела дополнительные закрывающие круглые скобки, и я надеюсь, что все остальное вы упомянули. –

+0

спасибо, на самом деле я нашел другой способ, но на этот раз мой вывод восьмеричный: D \ 347 0.006665: D :))) \ 347 is ç. – jekyll