У меня есть входная строка, содержащая символы разных размеров, например const char * input = "aadđ€€¢¢"
.
strlen
дал результат 15, что означает, что в то время как «aad» занимает всего 3 байта, другие специальные символы занимают по 2 или более байта каждый.
Как я могу вырезать символы, которые помещаются в 6 байтов от начала этой строки? Это означает, что в этом случае будет использоваться только «aadđ», потому что aadđ€ будет занимать 8 байтов.
Я пробовал обычные методы разделения символов, но пока ни один из них не работал. Редактировать: потому что широкий символ может быть разделен посередине, и поэтому вместо этого я получу какой-то мусор или другой символ.
Привет, я бы с удовольствием принял решение и на C++. Но я работаю с ограниченной средой, поэтому принимаются только стандартные библиотеки.
Какую кодировку вы используете? Кроме того, какой язык, не все языки можно разделить с помощью стандартных библиотечных функций. Это особенно верно для любого языка, не использующего латинский алфавит.
Что вам нужно, так это способ извлечения наборов символов, представляющих потенциально многобайтовую последовательность.
Связано с предположением, что вы можете использовать пробел для разделения stackoverflow.com/q/236129/332733
Вопрос кодировки касается «-fexec-charset» вашей компиляции или эквивалента. ("-fsource-charset" - это не информационный вопрос, это просто фундаментальное требование.)
Спасибо вам, ребята. Ввод поступает со смартфона на другое устройство, поэтому я не знал, как с этим справиться. Кодировка - UTF-8, поэтому я почитаю об этом подробнее, чтобы решить эту проблему.
Я проголосовал за повторное открытие, потому что этот вопрос явно не об отладке. В нем также есть четкая постановка проблемы: «Как я могу вырезать символы, которые умещаются в 6 байтов, от начала этой строки?»
Не могу понять вашу проблему, так как вы не описали проблему, с которой столкнулись. Но это должно сработать. Единственная проблема может заключаться в том, что широкий символ может быть разделен посередине, и вы можете получить другой символ.
char input2[7] = {0};
memcpy(input2, input, 6);
Если вы хотите получить длину wchar, вы можете использовать wcslen()
http://www.cplusplus.com/reference/cwchar/wcslen/
Спасибо. Ты прав. Проблема, с которой я сталкиваюсь, заключается в том, что широкий символ может быть разделен посередине, и у меня есть другой символ для отображения.
Здесь нельзя использовать wcslen()
. Широкие символы не являются чудодейственным решением для многобайтовых кодировок.
strlen
считает байты, а не символы.
Чтобы пройти по строке посимвольно, вы можете попробовать mblen
, который просматривает следующий символ в строке. Если кодирование строки не является UTF-8, вы должны соответствующим образом скорректировать вызов на setlocale
.
std::setlocale(LC_ALL, "en_US.utf8");
const char *input = "aadđ€€¢¢";
int clen;
mblen(0, 0);
for (const char *p = input; *p != 0; p += clen) {
clen = mblen(p, 4);
std::cout << p << ", clen = " << clen << '\n';
}
Получить ровно 6 байтов может оказаться сложно, потому что это может остановиться на полпути в многобайтовом символе.
int len = 0, clen;
mblen(0, 0);
for (const char *p = input; *p != 0 && len < 6; p += clen, len += clen) {
clen = mblen(p, 4);
}
char buf[10];
strncpy(buf, input, len);
buf[len] = 0;
Это остановится, как только будет достигнуто 6 байтов или больше.
Чтобы получить не более 6 байтов, вычтите последний символ перед копированием, если есть переполнение
if (len > 6)
len -= clen;
Спасибо, Олаф. Ваше решение решило мою проблему.
Вам нужно понимать разницу между «байтами» и «символами».
Байт — наименьшая единица памяти компьютера, содержит 8 бит информации. Символ (точнее, кодовая точка Unicode) — это число от 0 до 0x10FFFF, представленное одним или несколькими байтами, в зависимости от используемой кодировки. Символ связан с некоторым «глифом», изображением, которое является частью различных шрифтов.
Символы с кодами от 0 до 127 (обычно называемые «символами ASCII», но технически называемые блоками «Элементы управления C0 и базовая латынь») кодируются одним байтом. К ним относятся английские буквы, цифры и некоторые знаки препинания. Остальные символы кодируются несколькими байтами. Пожалуйста, посмотрите UTF-8 и UTF-16 для некоторых примеров того, как делается кодировка.
Чтобы ответить на ваш вопрос, учитывая строку в вашем примере, вы можете вырезать 6 байты в начале строки, но последние байты могут не представлять допустимый символ. В UTF-8 это будет «префиксный» байт, за которым будет следовать от одного до трех байтов, чтобы сформировать полную кодовую точку.
UTF-8, UTF-16 и UTF-32 — это кодировки одного и того же Unicode кодовые точки. Из-за композиции может потребоваться более одной кодовой точки для представления одного глиф, который вы бы распознали как символ. Выяснение этой последней части — задача для такой библиотеки, как ICU. Для большинства простых целей вы можете довольно легко проверить длину байтов для кодовых точек UTF-8. Почитайте про кодировку в Википедии.
@KhouriGiordano Вы правы, я совсем забыл о композиции. Я не уверен, что добавление еще одного уровня абстракции улучшит понимание ОП :). Я изменю ответ на вики сообщества, пожалуйста, не стесняйтесь редактировать. Или предоставить свой собственный, конечно.
«Обычно называется «символами ASCII», но это не совсем правильное название»: верно, в контексте набора символов Unicode это блок Элементы управления C0 и базовая латынь.
Спасибо. Я посмотрю UTF-8, чтобы понять, как делается кодировка для решения этой проблемы.
Вы используете строку в стиле C. Ваш вопрос тогда о языке C? C или C++: выберите один.