Вопросы при обновлении кода сканера для использования ICU - PullRequest
5 голосов
/ 29 мая 2011

Я работаю на элементарном лексическом сканере с ручным кодированием и хочу поддерживать вход UTF-8 (это уже не 1970!). Входные символы читаются из stdin или файла по одному за раз и помещаются в буфер до тех пор, пока не будут видны пробелы и т. Д. Я думал о написании моей собственной оболочки для fgetc(), которая вместо этого возвращала бы char[] байтов, составляющих символ UTF-8 и работать с результатом в виде строки ... это было бы достаточно просто, но стало бы скользким уклоном. Я бы предпочел не тратить время на повторное изобретение колеса, а вместо этого использовать существующую протестированную библиотеку, такую ​​как ICU . И теперь у меня есть код, не поддерживающий UTF-8, который работает с fgetc(), isspace(), strcmp() и т. Д., Который я пытаюсь обновить, чтобы использовать ICU. Это мой первый опыт работы с ICU, когда я перечитывал документацию и пытался найти примеры использования с помощью поиска кода Google, но все же есть некоторые недоразумения, которые, я надеюсь, кто-то сможет прояснить.

Функция u_fgetc() возвращает UChar, а u_fgetcx() возвращает UChar32 ... документация рекомендует использовать u_fgetcx() для чтения кодовых точек, поэтому я и начинаю с этого. Я придерживаюсь того же подхода, что и выше, но я помещаю UChar32 с в буфер вместо char с.

  • Как правильно сравнить символ с известным значением? Первоначально я был в состоянии сделать if (c == '+'), чтобы проверить, был ли знак плюс извлечен из ввода. GCC не жалуется, когда c является UChar32 (что тогда является сравнением между UChar32 и char), но действительно ли это правильно?

  • Мне удалось использовать strcmp() для сравнения буферизованных символов с известным значением, например if ((strcmp(buf, "else") == 0). ICU предоставляет u_strcmp(), и я думаю, что мне может понадобиться использовать макросы U_STRING_DECL и U_STRING_INIT для указания известного литерала, но я не уверен. Документация показывает, что они дают UChar[], хотя я предполагаю, что мне нужно UChar32[] ... и я все равно не знаю, как их правильно использовать. Любое руководство здесь будет приветствоваться.

  • После прочтения ряда числовых символов я преобразовал их с помощью strtol(), чтобы я мог работать с ними. Есть ли подобная функция, доступная в ICU, поскольку я сейчас конвертирую UChar32[]?

Ответы [ 2 ]

5 голосов
/ 01 июня 2011

UChar - для удержания кодовой единицы , а UChar32 - для удержания кодовой точки . Если ваш вход остается на Basic Multilingual Plane (BMP), UChar достаточно, и действительно большинство функций ICU работают на UChar[].

Настоятельно рекомендуется прочитать Руководство пользователя ICU , в котором объясняется большинство внутренних функций и передовой опыт.

  • Как правильно сравнивать символьную переменную Unicode с известным значением? Символ (или UChar или UChar32) - это просто еще один целочисленный тип с определенной шириной и подписью, который можно сравнить с другими целочисленными типами с обычными оговорками и ограничениями. Что касается определения значения символа, C99 (глава 6.4.3) предоставляет Универсальные имена символов запись: \u, за которой следуют четыре шестнадцатеричные цифры, или \U, за которыми следуют восемь шестнадцатеричных цифр с указанием ISO / IEC 10646 «короткий идентификатор». Область ниже 0x00a0 (за исключением 0x0024 '$', 0x0040 '@' и 0x0060 (backtick) зарезервирована (но может быть представлена ​​путем преобразования простой символьной константы в UChar). Также зарезервирован диапазон от 0xd800 до 0xdfff (для использования UTF-16).

  • Как определить строковые литералы Unicode? U_STRING_DECL и U_STRING_INIT действительно то, что вы ищете. (Как написано выше, ICU в основном работает на UChar[].) Если вы использовали C ++ вместо C, UNICODE_STRING_SIMPLE (опционально сопровождаемый getTerminatedBuffer(), чтобы снова получить UChar[]), обеспечивает гораздо больше удобный способ определения строковых литералов Unicode.

  • Как преобразовать строку Unicode, представляющую числовое значение, в значение этого числового значения? unum_parse() и его братья в unum.h помогут вам в этом.

2 голосов
/ 01 июня 2011
  1. Значение Unicode для PLUS SIGN равно U + 002B, а нормальное (Latin-1) значение для «+» также равно 0x2B (053, 43). То, что вы написали, достаточно безопасно, если кодовый набор основан на ASCII или ISO-8859-x. Стандарт C99 предусматривает Unicode (универсальные имена символов) форм \u0123 и \U00102345 (с 4 и 8 шестнадцатеричными цифрами), но предусматривает, что вы не можете указывать значения меньше \u00A0, например \u002B. Итак, я думаю, что вы написали правильно.

    Тем не менее, вы можете спасти себя в будущем, используя enum, например

     enum { PLUS_SIGN = '+' };
    

    определено в соответствующем заголовке и используется там, где вам нужен буквальный знак плюс. Таким образом, если ваше предположение (и мое предположение) неверно, у вас есть одно место для редактирования - заголовок.

    Замечу, что на странице Strings с ICU предполагается, что использование UTF-32 в приложении необычно.

  2. В чистом C вы, вероятно, использовали бы wcscmp(buf, L"else"), предполагая, что wchar_t в вашей системе эквивалентно uint32_t и / или UChar32. Кажется, есть способы использовать UnicodeString и UNICODE_STRING("..."), а затем ToUTF32() для создания строки UTF-32. Также могут быть более аккуратные способы.

  3. Существуют классы 'Форматирование', которые обрабатывают как форматирование, так и синтаксический анализ. Вы, вероятно, будете использовать классы, производные от NumberFormat class.

...