Как преобразовать строку из UTF8 в Latin1 в C / C ++?

У меня довольно простой вопрос, но я так и не смог найти решение:

Как я могу конвертировать в кодировке UTF8 string в кодировке latin1 string в C ++ без использования каких-либо дополнительных библиотек, таких как libiconv?

Каждый пример, который я смог найти, относится к преобразованию latin1 в UTF8?

5

Решение

typedef unsigned value_type;

template <typename Iterator>
size_t get_length (Iterator p)
{
unsigned char c = static_cast<unsigned char> (*p);
if (c < 0x80) return 1;
else if (!(c & 0x20)) return 2;
else if (!(c & 0x10)) return 3;
else if (!(c & 0x08)) return 4;
else if (!(c & 0x04)) return 5;
else return 6;
}

template <typename Iterator>
value_type get_value (Iterator p)
{
size_t len = get_length (p);

if (len == 1)
return *p;

value_type res = static_cast<unsigned char> (
*p & (0xff >> (len + 1)))
<< ((len - 1) * 6);

for (--len; len; --len)
res |= (static_cast<unsigned char> (*(++p)) - 0x80) << ((len - 1) * 6);

return res;
}

Эта функция вернет кодовую точку Unicode в p, Теперь вы можете конвертировать строку, используя

for (std::string::iterator p = s_utf8.begin(); p != s_utf8.end(); ++p)
{
value_type value = get_value<std::string::iterator&>(p));
if (value > 0xff)
throw "AAAAAH!";
s_latin1.append(static_cast<char>(value));
}

Никаких гарантий, код довольно старый 🙂

4

Другие решения

Вот вариант ответа фильма, который я написал для своих целей. Чуть более читабельным, возможно, немного медленнее. Мне не нужны были шаблоны, так как я всегда имел дело с char *и в моем случае я хотел заменить символы не-Latin1 на _. На всякий случай это кому-то поможет:

int GetUtf8CharacterLength( unsigned char utf8Char )
{
if ( utf8Char < 0x80 ) return 1;
else if ( ( utf8Char & 0x20 ) == 0 ) return 2;
else if ( ( utf8Char & 0x10 ) == 0 ) return 3;
else if ( ( utf8Char & 0x08 ) == 0 ) return 4;
else if ( ( utf8Char & 0x04 ) == 0 ) return 5;

return 6;
}

char Utf8ToLatin1Character( char *s, int *readIndex )
{
int len = GetUtf8CharacterLength( static_cast<unsigned char>( s[ *readIndex ] ) );
if ( len == 1 )
{
char c = s[ *readIndex ];
(*readIndex)++;

return c;
}

unsigned int v = ( s[ *readIndex ] & ( 0xff >> ( len + 1 ) ) ) << ( ( len - 1 ) * 6 );
(*readIndex)++;
for ( len-- ; len > 0 ; len-- )
{
v |= ( static_cast<unsigned char>( s[ *readIndex ] ) - 0x80 ) << ( ( len - 1 ) * 6 );
(*readIndex)++;
}

return ( v > 0xff ) ? 0 : (char)v;
}

// overwrites s in place
char *Utf8ToLatin1String( char *s )
{
for ( int readIndex = 0, writeIndex = 0 ; ; writeIndex++ )
{
if ( s[ readIndex ] == 0 )
{
s[ writeIndex ] = 0;
break;
}

char c = Utf8ToLatin1Character( s, &readIndex );
if ( c == 0 )
{
c = '_';
}

s[ writeIndex ] = c;
}

return s;
}

Тестовый код:

char s2[ 256 ] = "lif\xc3\xa9 is b\xc3\xa9tt\xc3\xa9r with acc\xc3\xa9nts";
Utf8ToLatin1String( s2 );
1

latin1 (ака ISO-8859-1) определяет первые 256 кодовых точек Unicode. Таким образом, в UTF-8, если ваш персонаж 8 бит, то он будет точно отображаться в latin1 эквивалент. Если длина больше 8 бит, то внутри latin1 и вы должны сопоставить его с каким-то «неизвестным персонажем» (например, \0 или же ?).

-2
По вопросам рекламы [email protected]