Как мне написать этот код C с использованием Unicode?

У меня был аналогичный вопрос о том, какой язык лучше всего подходит для этой задачи, и Perl был ответом. Но мне все еще любопытно, как решить эту проблему с помощью C.

Я хочу дать этой программе большой текстовый файл, заполненный образцами немецкого текста, взятыми из романов, газет, веб-страниц. Мне нужен частотный список всех слов в текстовом файле, отсортированный по наиболее распространенным словам. Мне нужен список из 3000 самых распространенных немецких слов.

Если бы это была просто проблема с ASCII, то для меня это было бы детской забавой. Прочитав все утро о Unicode, я действительно удивлен, какое это минное поле.

Как это делается в Си?

У меня был друг, который собирал что-то на Python, но он все еще новичок, и его код занял около 30 минут в текстовом файле размером 1,4 МБ.


person Korgan Rivera    schedule 31.03.2013    source источник
comment
Какова кодировка символов большого текстового файла, из которого состоит ваш корпус слов? UTF-8? UTF-16? Что-то другое?   -  person Adam Rosenfield    schedule 01.04.2013
comment
Я считаю, что это в основном одна строка в Python, игнорирующая импорт: print(Counter(re.findall(r'(?u)\w+', open('input.txt').read())).most_common(3000)). Не самый быстрый способ, но и 30 минут не займет.   -  person nneonneo    schedule 01.04.2013
comment
@AdamRosenfield Это UTF-8.   -  person Korgan Rivera    schedule 01.04.2013
comment
-1 за отсутствие исследований. Простой поиск [c] unicode здесь, в SO, дал бы вам несколько полезных результатов. Взгляните, например, на stackoverflow.com/questions/114611/ (и обратите внимание на ответ, который получил -8; игнорируйте любое упоминание wchar_t... это не имеет отношения к вашим потребностям).   -  person Jim Balter    schedule 01.04.2013
comment
Помечен за грубость. Никаких исследований не было видно. Я ничего не сказал обо всех вещах, просто искал SO для [c] unicode. Я дал вам хорошую помощь с помощью ссылки, которую я предоставил, но никогда больше. Удачи вам когда-либо получать здесь помощь, если вы оскорбляете людей, от которых хотите получить помощь.   -  person Jim Balter    schedule 01.04.2013
comment
P.S. Невозможно минусовать комментарии.   -  person Jim Balter    schedule 01.04.2013
comment
Кроме того, прочитайте часто задаваемые вопросы сайта перед публикацией, особенно stackoverflow.com/faq#etiquette. И это ответственность граждан SO голосовать за вопросы и ответы вверх и вниз, чтобы поддерживать и улучшать качество сайта... это то, что я сделал, согласно down">stackoverflow.com/privivities/vote-down По крайней мере, я указал причину; люди часто не делают.   -  person Jim Balter    schedule 01.04.2013


Ответы (5)


Это зависит от кодировки. Самый простой из них - UTF-8, в котором вы можете просто хранить строки в char* массивах. Удивительно, но для построения списка частот используется почти тот же код, что и в случае текста ASCII. Это своего рода магия UTF-8, но именно поэтому эта кодировка такая мощная!

Есть несколько вещей, которые вы должны помнить в этом случае:

  1. Unicode предоставляет больше белых символов, чем ASCII. Вам понадобится их список, чтобы знать, где слова разделены. К счастью, в в Википедии есть.

  2. Юникод не всегда однозначен. Бывают случаи, когда разные последовательности дают один и тот же символ. Обычно это происходит с составными персонажами: например. Немецкий Ä может быть представлен как:

    • character U+00C4 - single letter Ä
    • последовательность U+0041 U+0308 - латинская буква A и умляут над ней.

    К счастью, в немецком языке всего семь неанглийских символов: ÄäÖöÜüß. Вам нужно проверить, как выглядят их альтернативные варианты (например, здесь на страницах 4 и 5 вы должны найти все немецкие символы и их альтернативные формы).

Конечно, для решения обеих проблем вам также необходимо знать, как все ваши выводы представлены в UTF-8. Это описано в RFC 3629, стр. 3.

В случае других кодировок (или других языков) я бы предложил не заниматься этим самостоятельно, а использовать какую-то уже существующую библиотеку. Если вы используете Linux (или большинство других Unices), вы можете использовать функцию iconv (man 3 iconv) для преобразования вашего текста в UTF-8 и действовать, как я описал ранее.

Другой вариант — использовать какую-нибудь библиотеку, которая уже работает с различными вариантами Unicode. Самым мощным, вероятно, является ICU - Международные компоненты для Unicode. Ознакомьтесь с их руководствами, чтобы узнать, как выполнить свою задачу с его помощью.

person notsurewhattodo    schedule 31.03.2013

Вы не указали четко требования своей программы, но я могу думать только о двух аспектах, которые могут потребовать от вас внимания к личности персонажа:

  1. Если входной текст имеет смешанный регистр, вы можете сопоставить все слова с одним и тем же регистром, чтобы версии одного и того же слова в разных регистрах учитывались вместе.

  2. Если ввод находится в смешанной форме нормализации (некоторые символы предварительно составлены, другие разложены), вам необходимо выполнить нормализацию, чтобы гарантировать, что слова, которые отличаются только таким образом, подсчитываются вместе.

Если, например, ваш ввод был NFC со строчными буквами, программа, написанная только с учетом ASCII, отлично подойдет для вашей задачи. Поскольку это, вероятно, не так, вам необходимо оценить свои требования. Только для проблемы 1 (случай) вы, вероятно, можете обойтись, используя широкосимвольные функции stdio (или байт-ориентированные stdio и mbsrtowcs) и towlower для отображения регистра. Для проблемы 2 (нормализация) вам нужно будет либо использовать существующую библиотеку Unicode для C, либо создать свою собственную.

person R.. GitHub STOP HELPING ICE    schedule 31.03.2013
comment
Для немецкого языка tschüß в верхнем регистре соответствует TSCHÜSS, а ue является альтернативной формой для ü, поэтому towlower() не соответствует. - person ninjalj; 31.07.2014

Вы можете использовать строки wchar_t и функции, определенные в заголовочном файле wchar.h.

person Johnny Mnemonic    schedule 31.03.2013

Если вы можете сделать это без проблем в ASCII, это не должно быть намного сложнее в Unicode (по крайней мере, в C99).

Практически все стандартные библиотечные функции, работающие со строками и символами, имеют эквиваленты расширенных символов, и когда вы работаете с широкими символами, вам никогда не придется беспокоиться о базовой кодировке — один широкий символ представляет собой один фактический символ. Есть iswupper, towupper, wcslen и так далее.

Это предполагает, что вы работаете в простой среде (например, система UTF-8, текст UTF-8), поскольку локаль будет обрабатывать все. Если нет, то работы больше.

person teppic    schedule 31.03.2013

Возможно, вы захотите использовать для этого системные инструменты, это можно сделать, если языковой стандарт вашей системы установлен правильно. Вы можете легко использовать 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

РЕДАКТИРОВАТЬ:

Это очень близко к тому, что вы ищете.

person yeyo    schedule 01.04.2013
comment
В вашем сценарии знаки препинания входят в состав слов, и мне нужен отсортированный список, но я понимаю вашу точку зрения. Спасибо. - person Korgan Rivera; 01.04.2013