2015-10-16 7 views
3

Мне нужно преобразовать символы Doublebyte. В моем специальном случае Shift-Jis во что-то лучше обрабатывать, желательно со стандартным C++.C++ ShiftJIS to UTF8 conversion

следующий Вопрос закончилась без обходного: Doublebyte encodings on MSVC (std::codecvt): Lead bytes not recognized

Так ли кто-нибудь с предложением или ссылки о том, как справиться с этим преобразование с стандартом C++?

+0

«Лучше обращаться» за то, что именно? Только одно направление? (ShitJIS => что-то, но не somethingelse => ShiftJIS) – deviantfan

+0

Sry, для отображения в UTF-8, например. Только в одном направлении. Это было бы хорошо знать. – bob

ответ

1

Обычно я бы рекомендовал ICU, но для этого один, используя его слишком много накладных расходов.

Ниже приведена ссылка на файл, содержащий таблицу преобразования. Загрузите его в программе, например, в массиве/вектор uint8_t имени convTable (именно 25088 байт), то вы можете использовать следующие функции для преобразования строки ShiftJIS в UTF8 (как в std::string):

std::string sj2utf8(const std::string &input) 
{ 
    std::string output(3 * input.length(), ' '); 
    size_t indexin = 0, indexout = 0; 
    while(indexin < input.length()) 
    { 
     char group = ((uint8_t)input[indexin]) >> 4; 
     size_t offset = 0; 
     if(group == 0x8) offset = 0x100; 
     else if(group == 0x9) offset = 0x1100; 
     else if(group == 0xE) offset = 0x2100; 
     else group = 0; 
     if(group) 
     { 
      offset += (((uint8_t)input[indexin]) & 0xf) << 8; 
     } 
     else offset = input[indexin]; 
     indexin++; 
     if(group && indexin < input.length()) 
     { 
      offset |= (uint8_t)input[indexin++]; 
     } 
     offset <<= 1; 


     uint16_t value = (convTable[offset] << 8) | convTable[offset + 1]; 
     if(value < 0x80) 
     { 
      output[indexout++] = value; 
     } 
     else if(value < 0x800) 
     { 
      output[indexout++] = 0xC0 | (value >> 6); 
      output[indexout++] = 0x80 | (value & 0x3f); 
     } 
     else 
     { 
      output[indexout++] = 0xE0 | (value >> 12); 
      output[indexout++] = 0x80 | ((value & 0xfff) >> 6); 
      output[indexout++] = 0x80 | (value & 0x3f); 
     } 
    } 
    output.resize(indexout); 
    return output; 
} 

Функция не проверяет, если вход корректные данные ShiftJIS, недопустимые символы будут генерировать пробелы в выходных данных UTF8 (не только из-за ' ' в коде, файл данных сделан таким образом тоже)

файл:
Загрузить: http://www.filedropper.com/shiftjis
Сгенерировано: ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT

Содержание:
Два байта большой Endian значения сырой Юникода (более чем в два байта не нужна)
Первые 256 символов (512 байт) для отдельных байт ShiftJIS символов, значение 0x20 для недопустимых.
Затем 3 * 256 * 16 символов для групп 0x8 ???, 0x9 ??? и 0xE ???
= 25088 байт

+0

Спасибо, что поделились своим кодом! Мне пока не удалось заставить его работать. Я прошел в std :: string, который должен быть приличным японским текстом, а вывод всегда равен 0. Любые предложения? – bob

+0

@Sascha Произошла ошибка, но это должно было повлиять только на текст ASCII, а не на японские символы. Обновленный код в ответе, он должен работать как есть. Вы уверены, что правильно загрузили массив? Откуда появляется вход, как вы можете проверить/распечатать вывод? – deviantfan

+0

Я прочитал весь файл с ifstream, поэтому у меня есть вектор с 25088 значениями, похожими на то, что я видел в двоичном редакторе. Я просто передаю строку со значениями, такими как «\ x83 \ x41» или аналогично, и вывод sj2utf8 всегда равен 0. – bob