LINUX.ORG.RU

  • Unicode != UTF-8
  • getchar работает только с «узкими» символами
  • кириллица::а кодируется в UTF-8 двумя code point-ми

Первый пункт самый важный

Deleted
()
Ответ на: комментарий от Deleted

кириллица::а кодируется в UTF-8 двумя code point-ми

Представление в code unit'ах кодируется всё же, а code point — это то, что они кодируют (0x0430 в данном случае).

xaizek ★★★★★
()

Незнаю что написали там, потому что сообщения неугодных блокируются, но я нашел способ, как получить нужное число. С помощью getwchar.

u0atgKIRznY5
() автор топика

О, а получилось что видно, и видимо никто ничего плохого не написал. Спасибо всем за помощь.

u0atgKIRznY5
() автор топика

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

wchar не обязан быть юникодом...

#ifndef __STDC_ISO_10646__
#error "wchar_t wide characters have to be Unicode code points"
#endif

fsb4000 ★★★★★
()
Ответ на: комментарий от Deleted

Так то стоит en_US.UTF-8, но я менял для проверки на ru_RU.UTF-8. Также в программе менял и так и так с помощью set_locale.

u0atgKIRznY5
() автор топика

Чтобы было ясно почему 0xd0b0 надо, а не 0x0430.

char c[] = { 0xd0, 0xb0 };
printf ( "%s\n", c );

u0atgKIRznY5
() автор топика
Ответ на: комментарий от u0atgKIRznY5

Почему ты решил что надо 0xd0b0?

Всё корректно. Учи юникод.

#include <stdio.h>
#include <stdint.h>
#include <wchar.h>
#include <locale.h>

#ifndef __STDC_ISO_10646__
#error "wchar_t wide characters have to be Unicode code points"
#endif


union utf8
{
    wchar_t code;
    uint8_t bytes[sizeof (wchar_t)];
};

typedef union utf8 utf8;

int main(void)
{
    setlocale(LC_ALL, "");
    utf8 c = {0};
    c.code = getwchar();
    for (size_t i = 0; i < sizeof (wchar_t); ++i)
    {
        wprintf(L"byte[%zu]: 0x%.02hhX\n", i, c.bytes[i]);
    }
    
}
./a.out 
а
byte[0]: 0x30
byte[1]: 0x04
byte[2]: 0x00
byte[3]: 0x00

https://unicode-table.com/ru/0430/

Номер в Юникоде U+0430

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

+1

Чёт я туплю. Внутреннее представление implementation-defined(в данном случае UTF-32, вроде) и от внешнего зависит никак

Deleted
()
Ответ на: комментарий от fsb4000

Перед твоим сообщением написано, каков будет результат. К сожалению юникодом текст не печатается в printf. А так спасибо, вот подарок click

u0atgKIRznY5
() автор топика
Ответ на: комментарий от u0atgKIRznY5

Всё печатается.

Читай стандарт.

Кириллическая буква а в Unicode 0430.

Это дичь

char c[] = { 0xd0, 0xb0 };

Нужно так:

#include <stdio.h>

int main(void)
{
    printf("%s\n", u8"\u0430");
}

fsb4000 ★★★★★
()
Ответ на: комментарий от u0atgKIRznY5

Если нужно именно UTF8 представление(именно там будет 0xd0, 0xb0 ), то тогда только считывать строки целиком (потому что один UTF8 символ может занимать разное количество байт)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str[] = u8"\u0430";
    size_t len = strlen(str);
    for (size_t i = 0; i < len; ++i)
    {
        printf("str[%zu]: 0x%.02hhX\n", i, str[i]);
    }

    char buffer[512] = {0};
    scanf("%511s", buffer);
    printf("buffer = %s\n", buffer);

    len = strlen(buffer);
    for (size_t i = 0; i < len; ++i)
    {
        printf("buffer[%zu]: 0x%.02hhX\n", i, buffer[i]);
    }    
}
./a.out str[0]: 0xD0
str[1]: 0xB0
а
buffer = а
buffer[0]: 0xD0
buffer[1]: 0xB0
fsb4000 ★★★★★
()
Ответ на: комментарий от deep-purple

Прикольно. Спасибо, что поделился.

Используя твои if .. else if удалось разобрать utf8 строку по буквам.

./a.out 
H
e
l
l
o
,
 
日
本
語
と
 
М
и
р
!

Так и свою функцию read_utf8_char можно написать если понадобится...

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Ладно, хоть и оффтоп так как тег темы C, а я писал на С++, но решил поделиться и кодом разбора. Понятно что есть куда улучшать, но может кому-то будет полезно для старта

#include <string>
#include <iostream>
#include <cinttypes>
#include <ciso646>
#include <cassert>

using namespace std;

static string get_utf8_character(const char* str)
{
    assert (str != nullptr);

    size_t len{0};
    uint8_t byte{static_cast<uint8_t>(*str)};
    if (byte < 128) {
        len = 1;
    } else if (byte < 224) {
        len = 2;
    } else if (byte < 240) {
        len = 3;
    } else if (byte < 248) {
        len = 4;
    } else if (byte < 252) {
        len = 5;
    } else {
        len = 6;
    }
    return string(str, str + len);
}

class utf8string_iterator
{
    const char* s {nullptr};
public:
    explicit utf8string_iterator (const char* str)
        : s{str}
    {}
    string operator*() const
    {
        return get_utf8_character(s);
    }
    utf8string_iterator& operator++()
    {
        auto temp (get_utf8_character (s));
        s += temp.size();
        return *this;
    }
    bool operator!= (const utf8string_iterator) const
    {
        return (s != nullptr) and (*s != '\0');
    }
};


class utf8string_range
{
    const char* s {nullptr};
public:
    explicit utf8string_range (const char* str)
        : s{str}
    {}
    utf8string_iterator begin() const
    {
        return utf8string_iterator{s};
    }
    utf8string_iterator end() const
    {
        return utf8string_iterator{nullptr};
    }
};

int main()
{
    for (auto ut8_chars : utf8string_range("Hello, 日本語と Мир!"))
    {
        cout << ut8_chars << endl;
    }
}

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Писать программы явно не твоё.

anonymous
()
Ответ на: комментарий от fsb4000
#include <assert.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

#ifndef __cplusplus
#define nullptr ((void*)+0)
#endif

#ifndef __cplusplus
#ifndef thread_local
#define thread_local _Thread_local
#endif
#endif

static const char* get_utf8_character(const char* str)
{
    assert (str != nullptr);

    thread_local static char buffer[7] = {0};

    size_t len = 0;
    uint8_t byte = (uint8_t)(*str);

    if (byte < 128) {
        len = 1;
    } else if (byte < 224) {
        len = 2;
    } else if (byte < 240) {
        len = 3;
    } else if (byte < 248) {
        len = 4;
    } else if (byte < 252) {
        len = 5;
    } else {
        len = 6;
    }

    memcpy(buffer, str, len);
    buffer[len] = '\0';
    return buffer;
}

int main(void)
{
    
    for (const char *s = "Hello, 日本語と Мир!", *utf8_chars = get_utf8_character(s);
         *s != '\0';
         s+= strlen(utf8_chars), utf8_chars = get_utf8_character(s))
    {
        printf("%s\n",  utf8_chars);
    }
}
fsb4000 ★★★★★
()
Ответ на: комментарий от u0atgKIRznY5

getwchar получает 0x0430, а надо 0xd0b0, каким символом и является.
…а надо 0xd0b0, каким символом и является.
…0xd0b0, каким символом и является.
…0xd0b0

>>> chr(0xd0b0)
'킰'
>>> chr(0x0430)
'а'


Хм.

awesomelackware
()

Я уже свой деюникодер кидал сюда, впрочем кину ещë раз

int utfprocesschar(int in)
{
	static int m = -1, k = 0; //multibyte state
	static int uc = 0; //unicode char
	
	if( !in )
	{
		m = -1;
		k = 0;
		uc = 0;
		return 0;
	}

	// Get character length
	if(m == -1)
	{
		uc = 0;
		if( in >= 0xF8 )
			return 0;
		else if( in >= 0xF0 )
			uc = in & 0x07, m = 3;
		else if( in >= 0xE0 )
			uc = in & 0x0F, m = 2;
		else if( in >= 0xC0 )
			uc = in & 0x1F, m = 1;
		else if( in <= 0x7F)
			return in; //ascii
		// return 0 if we need more chars to decode one
		k=0;
		return 0;
	}
	// get more chars
	else if( k <= m )
	{
		uc <<= 6;
		uc += in & 0x3F;
		k++;
	}
	if( in > 0xBF || m < 0 )
	{
		m = -1;
		return 0;
	}
	if( k == m )
	{
		k = m = -1;
		return in;
	}
	return 0;
}


переделай в цикл с getchar, убери статики и оно будет потокобезопасно.

mittorn ★★★★★
()

дорогие всё никак не исчезающие любители приравнивать wchar к «юникоду»:

1) приведите выдержку из стандарта вашей любимой сишечки где wchar приравнен к «юникоду»

2) потрудитесь объяснить что такое «юникод». Вы вообще в курсе что это название стандарта и что способов кодирования юникода легко и непринуждённо наберётся с десяток в любом варианте применения?

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

Внутреннее представление implementation-defined

Я не утверждал, что это юникод

Deleted
()

Какой-то фестиваль кретинов итт. И никто ведь не удаляет и не уносит бред в толксы.

anonymous
()
Ответ на: комментарий от RazrFalcon

А что не так?

Ну noexcept не дописал к методам, конструкторам...

вместо

auto ut8_chars : 
Можно было
const auto& ut8_chars : 

А так, благодаря small string optimization, аллокаций не будет и в варианте c++, поэтому создание string для букв достаточно дешевое.

Благодарим C++11 за small string optimization...

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Благодарим C++11 за small string optimization...

Хм... А как тогда std::basic_string<> удовлетворяет следующему условию: &*(s.begin() + n) == &*s.begin() + n?

Deleted
()
Ответ на: комментарий от fsb4000

Точно, опять туплю. Спасибо за информацию

Deleted
()
Ответ на: комментарий от fsb4000

Вы даже не видите собственных проблем?

Вот зачем реализовывать свою, заведомо кривую функцию для разбора utf8? Откуда такая тяга к велосипедам?

RazrFalcon ★★★★★
()
Ответ на: комментарий от SuoiCat

getwchar()

Только не надо так делать с UTF-8, там переменный размер символов.

peregrine ★★★★★
()
Ответ на: комментарий от andreyu

Спасибо за ссылку. Простая, кроссплатформенная и соответствующая всем стандартам реализация.

anonymous
()
Ответ на: комментарий от anonymous

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

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.