Как прочитать строку юникода в виде отдельных символов ascii и определить, что это действительно юникод, самым быстрым способом?

Я делаю библиотеку, которая позволяет пользователю вставлять и искать пары ключ-значение в виде структуры данных trie. Когда я вставляю строку Unicode, она разбивается на 4 символа (utf-8) (что нормально), но каждый символ становится ‘?’. Поэтому я попытался использовать setlocale(LC_ALL, ""), но это не сработало (или, может быть, я просто не знаю, какие аргументы подходят для моего случая и где их вызывать). Я не особо забочусь о печати или чтении символа как такового. Все, что я хочу, это то, что это можно каким-то образом представить уникальным образом.

В моем трее есть ссылки вроде node *next[256].

Итак, все, что я хочу, это когда вставляется строка Unicode, она вставляется как уникальная комбинация, которая позволяет искать эту строку уникальным образом. Также мне нужен способ определить, что символ Юникода был разбит на 4 отдельных символа. Это потому, что, например, если в строке «wxyz» символ юникода «x» разбит на a, b, c, d, тогда в trie будет сохранено «wabcdyz». Но если бы я на самом деле искал строку wabcdyz (не unicode) , то он найдет запись для этой строки, но это будет несоответствие.

Вот программа, которая показывает, что символ Юникода разбивается на четыре символа ?:

#include <stdio.h>

int main()
{
    printf("Hello World");

    char a[] = "Ƃ";

    int i;
    for(i = 0 ; a[i] != '\0' ; ++i)
    {
        printf("%c", a[i]);
    }

    return 0;
}

По моему опыту символ utf-8 представлялся в 2 байта, 2 символа. Первый байт Utf начинается с 0xC0 - en.wikipedia.org/wiki/UTF-8, поэтому вы должны хранить символы в байтах (uint8/signed char)

Igor Galczak 22.05.2019 16:58

@IgorGalczak Символы UTF-8 могут иметь размер от одного до четырех байтов (если вы соблюдаете искусственное ограничение Unicode кодовыми точками 0x10FFFF) или от одного до шести (если вы придерживаетесь исходного определения UTF-8). Я подозреваю, что OP на самом деле получает UTF-16 или -32.

zwol 22.05.2019 17:03

@Mihir По задумке каждый байт многобайтовой последовательности UTF-8 имеет свой старший бит, поэтому они никогда не могут конфликтовать с символами ASCII. Пока ваша структура trie не забивает старший бит, она должна работать со строками UTF-8 точно так же, как и с ASCII, даже без явного знания кодировки. Однако, если ваши строки Unicode последовательно имеют четыре байта на символ, они, вероятно, не UTF-8, а UTF-32, с которыми гораздо сложнее работать. Пожалуйста, сообщите нам числовое значение каждого из четырех байтов в одном из проблемных символов.

zwol 22.05.2019 17:05

Однако, с другой стороны, каждый байт с очищенным старшим битом является допустимой однобайтовой кодовой последовательностью UTF-8, и любое количество таких байтов, соединенных вместе, является допустимым текстом в кодировке utf-8. Кроме того, существует множество последовательностей байтов, содержащих некоторые из них с установленным старшим битом, которые не являются допустимыми последовательностями кода UTF-8.

John Bollinger 22.05.2019 17:11

@zwol, понятно, все, что мне нужно, это чтобы один из этих символов Юникода мог быть представлен как один из символов от 0 до 256, потому что именно так моя попытка устанавливает ссылки. Он берет символ, преобразует его в числовое значение и соответственно переходит к следующей ссылке. Мне просто нужен самый точный и быстрый способ добиться этого.

Mihir Luthra 22.05.2019 17:12

"Строка Юникода"? В C у вас есть кодировка. Так вы имеете в виду "UTF-8"? Или вы делаете, как Python, интерфейс Unicode, и вы обрабатываете (и скрываете) детали?

Giacomo Catenazzi 22.05.2019 17:13

@Mihir, я заметил, что вы говорите «Unicode», но помечаете [utf-8] и описываете поведение, которое не соответствует UTF-8. UTF-8 — это в одну сторону представления текста Unicode, но не единственный способ.

John Bollinger 22.05.2019 17:14
stackoverflow.com/questions/3911536/…, в соответствии с этим я вижу способ определить, является ли последовательность байтов символом Юникода, но это похоже только на utf-8. Если моя реализация требует utf-32, что мне тогда делать?
Mihir Luthra 22.05.2019 17:15

@Mihir Невозможно преобразовать произвольный символ Юникода в число в [0, 255] без потери информации из-за принцип сортировки. Но ничего не пойдет не так, если вы дадите каждому байту многобайтовой последовательности UTF-8 свой собственный узел в дереве.

zwol 22.05.2019 17:18

@zwol, каждый байт в многобайтовой последовательности utf-8 получит узел в дереве. Одна проблема, с которой я все еще сталкиваюсь, заключается в том, что даже после setlocale() он все еще читает символы Юникода, такие как ‘?’ ‘? ‘?’ ‘?’. Как мне заставить его читать правильный символ?

Mihir Luthra 22.05.2019 17:28

@Mihir Два вопроса: (1) Почему ваша тестовая программа использует int a[] = "Ƃ"? Это определенно неправильно. Он даже не скомпилируется на моем компьютере. (2) Что выведет ваша программа, на твоем компьютере, если вы замените %c на %02x в вызове printf?

zwol 22.05.2019 18:00

Если я изменю тип элемента a на char в представленном коде, он отлично скомпилируется на моей машине и напечатает ожидаемый символ при запуске. Однако я отмечаю, что символ Ƃ не является членом базового набора исходных или исполняемых символов C. Реализация решает, принимать ли этот символ в виде самого себя в исходном коде C и чему он соответствует во время выполнения.

John Bollinger 22.05.2019 18:06

@zwol, я исправил, это было по ошибке.

Mihir Luthra 22.05.2019 18:10

@Mihir Все еще жду числовых значений этих байтов...

zwol 22.05.2019 18:10

@zwol, это печатает ffffffc6

Mihir Luthra 22.05.2019 18:15
строка юникода в виде отдельных символов ascii. Вот это оксюморон. В любом случае ваш код работает просто отлично. Я предполагаю, что у вас сломанная ОС без надлежащей поддержки UTF-8, но вы не делитесь какими-либо подробностями своей среды, поэтому дальнейший прогресс невозможен.
n. 1.8e9-where's-my-share m. 22.05.2019 18:16

@zwol, может быть, теперь я немного понимаю, ffffffc6 разбивается на индекс «-58», а такого индекса нет. Означает ли это, что каждый узел в последовательности utf-8 не находится в диапазоне 0-255?

Mihir Luthra 22.05.2019 18:19

@JohnBollinger, компилятор общего назначения, который не допускает Unicode в исходном коде, может быть совместимым, но это не делает его менее сломанным и бесполезным. Просто выбросьте его и получите тот, который делает правильные вещи. Дело не в том, что там какой-то дефицит.

n. 1.8e9-where's-my-share m. 22.05.2019 18:22

@Mihir Для меня это выглядит как нежелательное расширение знака, а не фактические байты 0xFF в вашем строковом литерале. Что будет напечатано, если вы измените всю строку printf на printf("%02x", (unsigned int)(unsigned char)a[i]);?

zwol 22.05.2019 18:23

@zwol, теперь c6. Ну наконец-то моя программа работает. Это было причиной того, что моя структура данных терпела неудачу. когда я изменил его на unsigned char *str, он работает правильно. Большое вам спасибо за вашу помощь.

Mihir Luthra 22.05.2019 18:33

@Mihir Предупреждение: шестнадцатеричный C6 - это только символ первый многобайтовой последовательности, составляющей op Ƃ. Вы также должны получить второй байт со значением hex 82.

Mr Lister 23.05.2019 13:43
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
21
150
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

UTF-8 — это механизм для последовательностей символов Юникода кодирование в виде последовательностей байтов, но не единственный способ. Unicode не подразумевает UTF-8, и технически UTF-8 также не подразумевает Unicode.

When I insert a unicode string, it breaks down into 4 characters(utf-8)

Это функция того, как вы храните строковые данные, и

  • это звучит сломано
  • это, вероятно, нет с использованием UTF-8, вопреки вашему утверждению

So all I want is when a unicode string gets inserted, it gets inserted as a unique combination which would make it possible to search that string uniquely.

Это относительно просто: кодируйте все свои строки одинаково. Кодирование всех их в UTF-8 было бы моим выбором, но вы также можете использовать любую другую кодировку без сохранения состояния, которая поддерживает все символы, которые могут появляться в ваших строках, например UTF-16 или UTF-32. Но вы должны использовать согласованную кодировку для всех символов всех строк.

Сделав это правильно, вам не обязательно делать что-то еще специальное, чтобы ваше дерево работало. Однако, если вы выберете UTF-16 или UTF-32, я бы предложил структурировать дерево вокруг размера их кодовых единиц. (16- или 32-битные соответственно). В этом нет необходимости, но, скорее всего, это даст преимущества в виде более мелких и, следовательно, более эффективных попыток.


* Обратите внимание, однако, что кодовые единицы UTF-16 и UTF-32 включают множество охватывающих байтов со значением 0, например 0x0031 и 0x00000200. Если вы рассматриваете их как последовательности байтов, а не как последовательности кодовых единиц, то вы должны учитывать это. В частности, вы должны избегать предположения, что отдельные нулевые байты служат терминаторами.

Это отвечает на большую часть моего вопроса. Но как мне вообще включить utf-8? например, я передаю Ƃ как строку для вставки. Когда я просматриваю строковый символ с помощью char, он читается как ‘?’ ‘? ‘?’ ‘?’. Как сделать так, чтобы он правильно читался?

Mihir Luthra 22.05.2019 17:33

@Mihir Мы действительно не можем вам больше помочь, пока вы не сообщите нам числовое значение каждого из этих четырех байтов. Я могу сказать вам прямо сейчас, что Ƃ, закодированный в UTF-8, должен создавать последовательность двухбайтовый 0xC6 0x82, так что это делает практически уверенным, что вы нет получаете UTF-8, но я до сих пор не знаю, что вы получаете являются. Также было бы полезно, если бы вы показали нам точную конструкцию кода, которую вы подразумеваете под «Я передаю Ƃ как строку для вставки».

zwol 22.05.2019 17:40

@JohnBollinger Вероятно, вам также следует упомянуть, что UTF-16 и -32 несовместимы с использованием однобайтовых \0 разделителей строк C; вместо этого вы можете использовать U+0000, но тогда вам придется работать с единицами кода, а не с байтами.

zwol 22.05.2019 17:41

@Mihir О, кроме того, нам нужно знать, используете ли вы Windows или нет. Ответ на ваши вопросы setlocale меняется в зависимости от этого.

zwol 22.05.2019 17:43

@zwol, я использую macOS. У меня есть такая строка, char str[] = “ Ƃ”;. если я перебираю каждый символ в этой строке до тех пор, пока не встретится «\ 0», он будет повторяться 4 раза и печатать «?» 4 раза. Так просто, он не разбивает символ Юникода правильно, вместо этого он производит «?». Извините, я новичок в этом деле. Я сделаю короткую программу, чтобы изобразить мою проблему и размещу ссылку здесь.

Mihir Luthra 22.05.2019 17:49

@Mihir, если предположить, что ваш компилятор соответствует C11 (для чего может потребоваться параметр командной строки), хорошей ставкой для литералов, как вы описываете, является использование литералов utf8: char str[] = u8"Ƃ";. Однако для данных, считанных из внешних источников, вам нужно либо предположить, что они будут закодированы в UTF-8, либо вы должны быть готовы перекодировать их в UTF-8 (что требует знания и поддержки исходной кодировки).

John Bollinger 22.05.2019 17:56

Я попробовал это на некоторых онлайн-компиляторах, и они выдают разные результаты. На моей машине это напечатало бы '?' 4 раза

Mihir Luthra 22.05.2019 17:56

@Mihir Mihir Я скопировал твою программу в твой вопрос. В будущем, пожалуйста, предоставьте пример кода, отредактировав вопрос, а не с помощью pastebin; мы хотим, чтобы вопросы и ответы имели смысл через много лет, а это не работает, если они зависят от ссылок на внешние сайты, которые уже могут быть недействительными. (Знаете ли вы, что можете редактировать свой вопрос? Крохотное серое слово edit под ссылками — это кнопка. Да, действительно. Да, это плохой дизайн пользовательского интерфейса. Извините.)

zwol 22.05.2019 17:58

@zwol, мне очень жаль. Мне в голову не пришло. Кроме того, всего за 1 неделю я присоединился к переполнению стека. Я обязательно сделаю это правильно в будущем

Mihir Luthra 22.05.2019 18:00

В любом случае, @Mihir, то, что печатается на экране, не соответствует тому, что вы видите в исходном файле, отражает несоответствие между предполагаемой и фактической кодировкой. Если это происходит, когда вы не испортили локаль, то это говорит о том, что фактическая кодировка вашего исходного файла отличается от того, что ожидает компилятор. На стороне вывода также может быть дополнительное несоответствие. В любом случае взаимодействующие компоненты должны знать и соглашаться с используемыми кодировками.

John Bollinger 22.05.2019 18:00

@Михир Не беспокойся. Мы все когда-то были новичками на этом сайте.

zwol 22.05.2019 18:01

Другие вопросы по теме