Создание строк с символами UTF-8 из данных

serial string data-type print char

Я печатаю некоторые изображения ASCII на последовательном мониторе из Arduino UNO, и с некоторым успехом. Однако использование строковых литералов требует больше памяти, чем хотелось бы. Я хотел попробовать создать строки/символы из других типов данных, чтобы можно было манипулировать данными и печатать ascii-изображения, не сохраняя их в строковых литералах.

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

Например, чтобы напечатать "▓" отлично работает как строковый литерал, но, судя по всему, не иначе.

Serial.println("▓");                         // работает отлично
Serial.println('▓');                         // char не может хранить значение
Serial.println(String('▓'));                 // char не может хранить значение
Serial.println(0x2593);                      // просто печатаем числовое значение
Serial.println((char)0x2593);                // char не может хранить значение
Serial.println((wchar_t)0x2593);             // не работает
Serial.println(String(0x2593));              // не работает
Serial.println(String((wchar_t)0x2593));     // не работает

Аналогично с write() вместо print():

Serial.write("▓");                  // Работает отлично
Serial.write('▓');                  // char не может хранить значение
Serial.write(0x2593);               // просто печатаем числовое значение
Serial.write((char)0x2593);         // char не может хранить значение
Serial.write((wchar_t)0x2593);      // не работает

Я также пытался получить строки новых компонентов из строкового литерала, используя substring() и charAt(). Ни то, ни другое не работает. Оба выдают � на выходе.

String((char)65) создает строку "A" из числового значения 65. Ни String((char)0x2593), ни String((wchar_t)0x2593) не дают желаемых результатов. Есть ли способ создать строку из числовых значений, которые слишком велики для хранения в «char»?

, 👍0

Обсуждение

попробуйте Serial.println("\u2593");, @jsotola

Я бы попробовал распечатать массивы байтов, содержащие сериализацию UTF-8, а не числовой код. Например \xe2 ,\x96, \x93 вместо \u2593., @RedGrittyBrick


1 ответ


3

Как вы заметили, Serial не знает, как обращаться с wchar_t. Если вы создаете свои строки алгоритмически из кода Unicode точки, вам необходимо преобразовать эти кодовые точки в UTF-8 для печати. я мне не известно ни о какой встроенной функции, которая бы это делала. Возможно, вы захотите найдите в менеджере библиотеки библиотеку, предоставляющую эту функцию.

Альтернативно вы можете написать преобразование самостоятельно: это не то сложный. Например, вот функция, которая преобразует любой код указывает из BMP (т. е. < 216) на строку UTF-8:

// Многобайтовый символ BMP с завершающим нулевым байтом.
struct Mbchar {
    char utf8[4];
};

// Преобразование широкого символа в UTF-8. Работает только внутри BMP.
Mbchar wchar_to_utf8(wchar_t c) {
    Mbchar result;
    if (c < 128) {               // 0xxx.xxxx
        result.utf8[0] = c;
        result.utf8[1] = 0;
    } else if (c < 2048) {       // 110x.xxxx 10xx.xxxx
        result.utf8[0] = 0xc0 | (c >> 6);
        result.utf8[1] = 0x80 | (c & 0x3f);
        result.utf8[2] = 0;
    } else {                     // 1110.xxxx 10xx.xxxx 10xx.xxxx
        result.utf8[0] = 0xe0 | (c >> 12);
        result.utf8[1] = 0x80 | (c >> 6 & 0x3f);
        result.utf8[2] = 0x80 | (c & 0x3f);
        result.utf8[3] = 0;
    }
    return result;
}

Имейте в виду, что в зависимости от используемого вами Arduino wchar_t может не поддерживает символы вне BMP. Arduino на базе AVR определенно нет.

Эту функцию можно использовать следующим образом:

Serial.println(wchar_to_utf8(0x2593).utf8);  // prints “▓”
,

Возможно, стоит добавить, что их использование '▓' не приведет к созданию типа 'wchar_t, а просто создаст какое-то бесполезное значение 'char. Им понадобится L'▓', который они смогут использовать вместе с вашим кодом в Serial.println(wchar_to_utf8(L'▓').utf8);, @timemage