Перейти к содержанию
    

Преобразовать UTF-16 в CP-866

17 минут назад, Arlleex сказал:

Кириллица + стандартный ASCII (коды 0...127), с возможностью отбраковки некорректно закодированных символов (по крайней мере, отсутствующих в CP-866).

У меня - аналогично. Только ->Win1251.

17 минут назад, Arlleex сказал:

Мне сначала прилетает поток байтов, которые (якобы) в UTF-16. Канал потенциально не надежный, т.е. мне надо каждый символ парсить на валидность в том числе, т.е. таблицу быстрого поиска организовать не достаточно.

У меня всё то же самое. Тоже ненадёжный и тоже - полная проверка с отбраковкой. Только UTF-8 и Win1251. И плюс ещё - у меня ещё и ESC-коды ходят по этому каналу. И парсер и их парсит (те участки я вырезал).

Этот парсер использую во многих проектах. Везде, где у меня управление/конфигурирование сделано через Putty-подобные терминалы. Т.е. - проверен многократно.

6 минут назад, kochevkv сказал:

Насколько я помню, кириллица в уникоде в u16 умещается.

UTF-8, UTF-16 - это просто разные способы упаковки Unicode-символов. А у Unicode кириллица занимает вполне определённый диапазон кодов. И ей достаточно 16 бит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 22.10.2024 в 22:07, Arlleex сказал:

Но вот просмотрел список символов в Unicode-таблице, сопоставимых с соответствующей частью в CP-866 и... кто в лес, кто по дрова. Какие-то ряды букв идут подряд, какие-то идут в разрыв уже. Т.е. банальным арифметическим преобразованием (смещением некого числа) не обойтись. Да и табличный метод не особо применить. Не уж то плодить кучу if(), или я чего-то не замечаю и все не так страшно?

Латиница + все русские буквы + символ '№' (остальное мне не нужно, расширенные 32-битные коды вовсе пропускаются)

static u32 convToCP866(u8 const src[], u8 dst[], u32 len) {
  u32 i = 0;
  
  while(len > 1) {
    u32 utf16 = *src++;
    
    utf16 |= *src++ << 8;
    
    if(utf16 < 0x80)
      dst[i++] = utf16;
    else if(utf16 >= 0x410 && utf16 < 0x450) {
      if((utf16 -= 0x390) >= 0xB0)
        utf16 += 0x30;
      
      dst[i++] = utf16;
    }
    else if(utf16 == 0x401)
      dst[i++] = 0xF0;
    else if(utf16 == 0x451)
      dst[i++] = 0xF1;
    else if(utf16 == 0x2116)
      dst[i++] = 0xFC;
    
    len -= 2;
  }
  
  return i;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

51 минуту назад, Arlleex сказал:

Латиница + все русские буквы + символ '№' (остальное мне не нужно, расширенные 32-битные коды вовсе пропускаются)

static u32 convToCP866(u8 const src[], u8 dst[], u32 len) {
  u32 i = 0;
  
  while(len > 1) {
    u32 utf16 = *src++;
    
...

Зачем так неоптимально?  :wink:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

Зачем так неоптимально?  :wink:

Да, по-другому уже немного написал, но суть та же

static u32 convToCP866(u16 const src[], u8 dst[], u32 len) {
  u32 i = 0;
  
  while(len-- > 0) {
    u32 utf16 = *src++;
    
    if(utf16 < 0x80)
      dst[i++] = utf16;
    else if(utf16 >= 0x410 && utf16 < 0x450) {
      if((utf16 -= 0x390) >= 0xB0)
        utf16 += 0x30;
      
      dst[i++] = utf16;
    }
    else if(utf16 == 0x401)
      dst[i++] = 0xF0;
    else if(utf16 == 0x451)
      dst[i++] = 0xF1;
    else if(utf16 == 0x2116)
      dst[i++] = 0xFC;
  }
  
  return i;
}


Всякими хитрыми преобразованиями сейчас некогда заниматься. Может быть потом вернусь к этому вопросу (нет).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

Всякими хитрыми преобразованиями сейчас некогда заниматься. Может быть потом вернусь к этому вопросу (нет).

Вот так:

u32 convToCP866_2(u16 const src[], u8 dst[], u32 len)
{
  u8 *s = dst;
  while ((s32)--len >= 0) {
    u32 j, c = *(s8 *)src++;
    if ((s32)(j = c) < 0) {
      j = 0xF0;
      if (c -= 0x401) {
        j = 0xF1;
        if (c -= 0x451 - 0x401) {
          j = 0xFC;
          if (c != 0x2116 - 0x451) {
            if ((c = c + 0x451 - 0x410) >= 0x450u - 0x410u) continue;
            if (c >= 0x30) c += 0x30;
            c += 0x80;
          }
        }
      }
    }
    *s++ = j;
  }
  return s - dst;
}

вроде получается покороче и побыстрее.  :smile:

По-крайней мере при Medium-оптимизации IAR. 60 байт против 98-и исходных.

Накидал по-быстрому. Может конечно где напутал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да на самом деле даже мой вариант компилятор CLang перетасовал на свой вкус так, что от моего там остался только LDRH и декремент счетчика в конце😄

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, Arlleex сказал:

Да на самом деле даже мой вариант компилятор CLang перетасовал на свой вкус так, что от моего там остался только LDRH и декремент счетчика в конце😄

И какой размер у него получился в итоге?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может не в тему, просто столкнулся с такой фигней, в rust-е стандартные строки utf-16 и есть их преобразование в байты. Наверно с учётом всех исключений и всей этой разноразмерности (я в ютф не вникал).

Предполагаю, что растовские сорцы можно понять, если даже раньше не

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, Arlleex сказал:

Латиница + все русские буквы + символ '№' (остальное мне не нужно, расширенные 32-битные коды вовсе пропускаются)

У меня много где используется символ '°' (Unicode==0xB0). Температуры, угловые градусы (для управления моторами и данные гироскопа).

А вот '№' никогда не требовался.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 минут назад, jcxz сказал:

У меня много где используется символ '°' (Unicode==0xB0). Температуры, угловые градусы (для управления моторами и данные гироскопа).

А вот '№' никогда не требовался.

У меня поезд, на маршрутных табло никогда градуса не будет. А вот номер - вполне может быть, наверное. Какая-нибудь надпись типа "Тупик №234" (для маршрутов внутри депо).
 

1 час назад, jcxz сказал:

И какой размер у него получился в итоге?

По ходу отладки выяснил, что мне нужно разворачивать декодированную строку в буфере-приемнике, т.е. класть в dst в виде "АБВГД" -> "ДГВБА", поэтому *src++ заменил на *src--. Листинг

0x080017D6 2100      MOVS          r1,#0x00
    31:   while(len-- > 0) { 
0x080017D8 F242622C  MOVW          r2,#0x262C
0x080017DC F2C20200  MOVT          r2,#0x2000
0x080017E0 EB020240  ADD           r2,r2,r0,LSL #1
    32:     u32 utf16 = *src--; 
    33:      
0x080017E4 F8322C02  LDRH          r2,[r2,#-0x02]
    34:     if(utf16 < 0x80) 
    35:       dst[i++] = utf16; 
0x080017E8 2A7F      CMP           r2,#0x7F
0x080017EA D90B      BLS           0x08001804
    36:     else if(utf16 >= 0x410 && utf16 < 0x450) { 
0x080017EC F5A26382  SUB           r3,r2,#0x410
0x080017F0 B29B      UXTH          r3,r3
0x080017F2 2B3F      CMP           r3,#0x3F
0x080017F4 D812      BHI           0x0800181C
    37:       if((utf16 -= 0x390) >= 0xB0) 
    38:         utf16 += 0x30; 
    39:        
    40:       dst[i++] = utf16; 
    41:     } 
0x080017F6 F5A27364  SUB           r3,r2,#0x390
0x080017FA 2BAF      CMP           r3,#0xAF
0x080017FC BF88      IT            HI
0x080017FE F10203A0  ADD           r3,r2,#0xA0
0x08001802 461A      MOV           r2,r3
0x08001804 F242632C  MOVW          r3,#0x262C
0x08001808 F2C20300  MOVT          r3,#0x2000
0x0800180C 440B      ADD           r3,r3,r1
0x0800180E 3101      ADDS          r1,r1,#0x01
0x08001810 F88321FB  STRB          r2,[r3,#0x1FB]
0x08001814 3801      SUBS          r0,r0,#0x01
0x08001816 D1DF      BNE           0x080017D8
0x08001818 E0EB      B             0x080019F2
0x0800181A BF00      NOP           
    42:     else if(utf16 == 0x401) 
0x0800181C F2404301  MOVW          r3,#0x401
0x08001820 429A      CMP           r2,r3
0x08001822 D00B      BEQ           0x0800183C
0x08001824 F2421316  MOVW          r3,#0x2116
0x08001828 429A      CMP           r2,r3
0x0800182A D005      BEQ           0x08001838
0x0800182C F2404351  MOVW          r3,#0x451
0x08001830 429A      CMP           r2,r3
0x08001832 D1EF      BNE           0x08001814
0x08001834 22F1      MOVS          r2,#0xF1
0x08001836 E7E5      B             0x08001804
0x08001838 22FC      MOVS          r2,#0xFC
0x0800183A E7E3      B             0x08001804
0x0800183C 22F0      MOVS          r2,#0xF0
0x0800183E E7E1      B             0x08001804


На самом деле мне не очень важно, сколько оно будет занимать, главное чтобы работало и (если бонусом) побыстрее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 минут назад, Arlleex сказал:

поезд, на маршрутных табло никогда градуса не будет

Сейчас в любом транспорте показов разных температур навалом, на некоем служебном табло забортная температура вполне может быть указана как причина отмены рейса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, Plain сказал:

Сейчас в любом транспорте показов разных температур навалом, на некоем служебном табло забортная температура вполне может быть указана как причина отмены рейса.

На табло внутри вагона градусы показываются. У меня табло намордное - т.е. лобовое, т.е. только маршрут следования и ничего более.

2 часа назад, jcxz сказал:

Накидал по-быстрому. Может конечно где напутал.

Не, тот вариант не работает корректно. Я особо в код не вникал, ибо там какая-то магия происходит, но сразу кинулась в глаза строчка

u32 j, c = *(s8 *)src++;
    if ((s32)(j = c) < 0) {

которая никогда не зайдет в этот if() при любых входящих символах из списка ASCII + А...Я + а...я + Ё + ё + №🙂

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Arlleex сказал:

Не, тот вариант не работает корректно. Я особо в код не вникал, ибо там какая-то магия происходит, но сразу кинулась в глаза строчка

u32 j, c = *(s8 *)src++;
    if ((s32)(j = c) < 0) {

которая никогда не зайдет в этот if() при любых входящих символах из списка ASCII + А...Я + а...я + Ё + ё + №🙂

Да, там перепутал. У вас же не UTF-8, а UTF-16. Исправил:

u32 convToCP866(u16 const src[], u8 dst[], u32 len)
{
  u8 *s = dst;
  while ((s32)--len >= 0) {
    u32 j, c = *src++;
    if ((s32)(j = (s8)c) < 0) {
      j = 0xF0;
      if (c -= 0x401) {
        j = 0xF1;
        if (c -= 0x451 - 0x401) {
          j = 0xFC;
          if (c != 0x2116 - 0x451) {
            if ((j = c + 0x451 - 0x410) >= 0x450u - 0x410u) continue;
            if (j >= 0x30) j += 0x30;
            j += 0x80;
          }
        }
      }
    }
    *s++ = j;
  }
  return s - dst;
}

 

3 часа назад, Arlleex сказал:

Листинг

Как-то многовато: 0x1840-0x17D6 = 106 байт! Мой вариант (выше) = 68 байт:

          u32 convToCP866(u16 const src[], u8 dst[], u32 len)                          
          {                                                                            
                  _Z11convToCP866PKtPhm: (+1)                                          
00000000   0xB570             PUSH     {R4-R6,LR}                                      
            u8 *s = dst;                                                               
00000002   0x460B             MOV      R3,R1                                           
00000004   0xF641 0x46C5      MOVW     R6,#+7365                                       
00000008   0xE018             B.N      ??convToCP866_0                                 
            while ((s32)--len >= 0) {                                                  
              u32 j, c = *src++;                                                       
                  ??convToCP866_1: (+1)                                                
0000000A   0xF830 0x4B02      LDRH     R4,[R0], #+2                                    
              if ((s32)(j = (s8)c) < 0) {                                              
0000000E   0xB265             SXTB     R5,R4                                           
00000010   0x2D00             CMP      R5,#+0                                          
00000012   0xD511             BPL.N    ??convToCP866_2                                 
                j = 0xF0;                                                              
00000014   0x25F0             MOVS     R5,#+240                                        
                if (c -= 0x401) {                                                      
00000016   0xF2A4 0x4401      SUBW     R4,R4,#+1025                                    
0000001A   0xB16C             CBZ.N    R4,??convToCP866_2                              
                  j = 0xF1;                                                            
0000001C   0x25F1             MOVS     R5,#+241                                        
                  if (c -= 0x451 - 0x401) {                                            
0000001E   0x3C50             SUBS     R4,R4,#+80                                      
00000020   0xBF1C             ITT      NE                                              
00000022   0x25FC             MOVNE    R5,#+252                                        
00000024   0x42B4             CMPNE    R4,R6                                           
                    j = 0xFC;                                                          
                    if (c != 0x2116 - 0x451) {                                         
00000026   0xD007             BEQ.N    ??convToCP866_2                                 
                      if ((j = c + 0x451 - 0x410) >= 0x450u - 0x410u) continue;        
00000028   0xF104 0x0541      ADD      R5,R4,#+65                                      
0000002C   0x2D40             CMP      R5,#+64                                         
0000002E   0xD205             BCS.N    ??convToCP866_0                                 
                      if (j >= 0x30) j += 0x30;                                        
00000030   0x2D30             CMP      R5,#+48                                         
00000032   0xBF28             IT       CS                                              
00000034   0x3530             ADDCS    R5,R5,#+48                                      
                      j += 0x80;                                                       
00000036   0x3580             ADDS     R5,R5,#+128                                     
                    }                                                                  
                  }                                                                    
                }                                                                      
              }                                                                        
              *s++ = j;                                                                
                  ??convToCP866_2: (+1)                                                
00000038   0xF803 0x5B01      STRB     R5,[R3], #+1                                    
            }                                                                          
                  ??convToCP866_0: (+1)                                                
0000003C   0x1E52             SUBS     R2,R2,#+1                                       
0000003E   0xD5E4             BPL.N    ??convToCP866_1                                 
            return s - dst;                                                            
00000040   0x1A58             SUBS     R0,R3,R1                                        
00000042   0xBD70             POP      {R4-R6,PC}       ;; return                      
          }                                                                            
3 часа назад, Arlleex сказал:

главное чтобы работало и (если бонусом) побыстрее.

Должно работать. И команд меньше - может по-быстрее будет. По крайней мере - выполнившихся условных переходов внутри цикла должно быть не много.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Завтра проверю ради интереса.

P.S. Хотя все равно уже вижу, что работать не будет правильно😉

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

22 часа назад, Arlleex сказал:

P.S. Хотя все равно уже вижу, что работать не будет правильно😉

Почему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...