Squeak.ru - шаблоны программирования

Печать символов Unicode с помощью write(2) в c

Я работаю над небольшим фрагментом кода, который выводит символы на экран и должен поддерживать весь Unicode, содержащийся в wchar_t, и я ограничен только write(2). Мне удалось напечатать смайлик, используя:

write(1, "\U0001f921", 6);

Так что \U кажется правильным. Однако я не могу преобразовать wchar_t в правильную управляющую последовательность, т.е. преобразовать wchar_t c = L'????'; в \U0001f921

Могу ли я даже сделать это в C?

Большое спасибо.

14.12.2017

  • Вы, вероятно, хотите UTF-8 14.12.2017
  • Да, может быть. Как бы я пошел о преобразовании? 14.12.2017

Ответы:


1

Я работаю над небольшим фрагментом кода, который выводит символы на экран и должен поддерживать весь Unicode, содержащийся в wchar_t, и я ограничен только записью (2).

Это проблематичное сочетание требований. В частности, представление символов wchar_t может очень плохо сочетаться с использованием write() для вывода.

В целом, здесь есть несколько проблем, среди них:

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

Обратите внимание, что этот C указывает только довольно небольшой набор символов, которые должны присутствовать в наборе символов выполнения. В нем могут присутствовать дополнительные, «расширенные» символы, и ваши эмодзи попадут в эту категорию. Работа с расширенными символами через стандартные интерфейсы C немного мягка, поскольку стандарт предоставляет реализациям большую свободу в том, как они там работают.

Так что \U кажется правильным.

\U вводит «универсальное имя персонажа». Важно понимать, что во время компиляции эти последовательности преобразуются в элементы набора символов выполнения.

Однако я не могу преобразовать wchar_t в правильную escape-последовательность, т.е. преобразовать wchar_t c = L'????'; в \U0001f921

Небезопасно предполагать, что «????» может быть представлен непосредственно в исходном наборе символов, чтобы использовать его буквально в исходном коде. Это зависит от вашей реализации C. Универсальное имя персонажа безопаснее. Кроме того, если вам нужна константа широкого символа, вы можете попробовать L'\U0001f921', но есть большая вероятность, что wchar_t не может представлять этот символ. В частности, многие реализации имеют 16-битный wchar_t, и вряд ли они смогут поддерживать вашего персонажа как (одиночного) wchar_t.

Возможно, вам больше повезет с широким строковым литералом: L"\U0001f921", но это полезно для вас, прежде всего, если вы работаете с функциями, специфичными для широких символов, которые будут выполнять соответствующие преобразования кодирования для вас. write() не будет выполнять такие преобразования, поэтому получение желаемого результата будет зависеть от конфигурации вашей среды выполнения. Я считаю, что ваш первоначальный подход с обычным строковым литералом с большей вероятностью сработает.

Если вы хотите, и если вы можете использовать функции C2011, вы также можете выразить (обычный) строковый литерал, который определен для кодирования в UTF-8, независимо от фактического набора символов выполнения. Форма для этого будет u8"\U0001f921". Опять же, получение желаемого результата таким образом зависит от вашей среды. Литералы UTF-8 лучше подходят для взаимодействия с интерфейсами, которые специально определены для использования UTF-8.

Могу ли я даже сделать это в C?

Небезопасно предполагать, что ваш эмодзи может быть представлен одним объектом типа wchar_t. Могут быть реализации C, которые его поддерживают, но я думаю, что они необычны.

Последнее замечание: этот код...

write(1, "\U0001f921", 6);

... почти наверняка демонстрирует неопределенное поведение в результате выхода за пределы массива char, который вы представляете write(). Я не вижу правдоподобного сценария, в котором он длиннее 5 символов, но вы пишете 6, превышая по крайней мере 1. Если внутреннее представление UTF-8, тогда этот массив будет иметь длину 4 - три байта, кодирующие символ и один для конца строки.

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

const char *emoji = "\U0001f921";
write(1, emoji, strlen(emoji));
14.12.2017
  • Ладно, думаю, у меня есть хорошая база для работы. Большое спасибо за запись. Я должен был добавить, что я ориентируюсь на OSX, и совместимость с другими системами на самом деле меня не волнует. Так что я поэкспериментирую с вашими советами и попытаюсь реализовать эти чертовы символы юникода... 14.12.2017
  • Итак, я проверил, и ввод, который я получаю, не имеет форму \Uxxxxx, как я думал. Я получаю LString ...., так что мне действительно нужно преобразовать число в правильный символ, не так ли? 14.12.2017
  • @Rogue, я не уверен, о чем ты спрашиваешь. Представление символа в памяти компьютера является числом или их последовательностью. Возможно, вас смущает то, как отладчик представляет вам память. В любом случае, вполне возможно, что вам нужно будет конвертировать между различными (числовыми) представлениями ваших персонажей, но вы не дали мне никаких оснований сказать что-то конкретное об этом. 14.12.2017
  • Ну, для упрощения, моя функция принимает ввод в виде одного wchar_t, который вызывается так: print_unicode(L'é');, но это означает, что я не могу использовать свою удобную технику денди \Uxxxx, потому что я получаю только часть xxxx, а не полный \Uxxxx. Не уверен, что это имеет смысл... 14.12.2017
  • @Rogue, обратитесь к той части моего ответа, где я заметил, что один wchar_t может даже не представлять вашего конкретного персонажа. Очень похоже на то, с чем вы столкнулись. Для этого нет обходного пути, кроме перепроектирования ваших сигнатур функций. 14.12.2017
  • В итоге я решил это, преобразовав кодовые точки в правильные байты UTF-8. Поскольку я ориентируюсь только на OSX, я буду продолжать использовать wchar_t, который, согласно моему тестированию, хорошо подходит. Спасибо за подробный вклад! 16.12.2017
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...