2014-05-15 14 views
6

Sto provando a convertire un UTF-8 string in un ISO-8859-1 char* da utilizzare nel codice legacy. L'unico modo che sto vedendo per farlo è con iconv.Converti stringa da UTF-8 a ISO-8859-1

Preferirei assolutamente una soluzione C++ completamente basata su string, quindi chiamare lo .c_str() sulla stringa risultante.

Come posso fare? Esempio di codice, se possibile, per favore. Sto bene usando iconv se è l'unica soluzione che conosci.

+0

Che suona come un potenziale grande progetto - ed esattamente il genere di cose una libreria come iconv è buono per. Cosa c'è di sbagliato nel farlo nel modo giusto? –

+0

Sto bene usando iconv se questo è l'unico modo disponibile per farlo. Non è sicuramente la soluzione C++ più elegante che si possa immaginare. Qualcosa come 's.toEncoding (" ISO-8859-1 ")' sarebbe molto più elegante. Il mio punto è, anche se lo sto facendo in iconv, non mi è chiaro come usare la libreria con l'input 'string'. –

+0

Non è sicuro, ma potrebbe essere utile: http://www.openldap.org/lists/openldap-devel/200304/msg00123.html – gerbit

risposta

6

Primo convertito Unicode da UTF-8 a 32 bit.

Quindi tenere i valori che sono nel range da 0 a 255.

Questi sono i punti di codice Latin-1, e per altri valori, decidere se si desidera per il trattamento che come un errore o forse sostituire con il codice di punto 127 (il mio preferito, l'ASCII "del") o un punto interrogativo o qualcosa del genere.


libreria standard Il C++ definisce una specializzazione std::codecvt che può essere utilizzato,

template<> 
codecvt<char32_t, char, mbstate_t> 

C++ 11 §22.4.1.4/3: “ la specializzazione codecvt <char32_t, char, mbstate_t> converte tra UTF-32 e schemi di codifica UTF-8 ”

+0

Funziona bene, semplicemente perché Unicode è stato definito come un superset di ISO-8859- 1 per cominciare. Vedi http://en.wikipedia.org/wiki/Unicode#Origin_and_development P.S. come punto di partenza per la conversione potrei suggerire http://stackoverflow.com/a/148766/5987 –

7

Ho intenzione di modificare il mio codice from another answer per implementare il suggerimento da Alf.

std::string UTF8toISO8859_1(const char * in) 
{ 
    std::string out; 
    if (in == NULL) 
     return out; 

    unsigned int codepoint; 
    while (*in != 0) 
    { 
     unsigned char ch = static_cast<unsigned char>(*in); 
     if (ch <= 0x7f) 
      codepoint = ch; 
     else if (ch <= 0xbf) 
      codepoint = (codepoint << 6) | (ch & 0x3f); 
     else if (ch <= 0xdf) 
      codepoint = ch & 0x1f; 
     else if (ch <= 0xef) 
      codepoint = ch & 0x0f; 
     else 
      codepoint = ch & 0x07; 
     ++in; 
     if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) 
     { 
      if (codepoint <= 255) 
      { 
       out.append(1, static_cast<char>(codepoint)); 
      } 
      else 
      { 
       // do whatever you want for out-of-bounds characters 
      } 
     } 
    } 
    return out; 
} 

L'input UTF-8 non valido restituisce caratteri interrotti.

+0

In realtà, ho UTF-8 'stringa' in arrivo. Se lo hai fatto' stringa'-a-'stringa ' sarebbe perfetto. –

+0

@ChrisRedford, basta chiamarlo con 'mystr.c_str()'. Mi piace avere l'input 'const char *' perché è più flessibile. –

+0

Poiché l'input proviene da un 'std :: string', basta sostituire' const char * in' con 'const std :: string & in', e quindi creare una variabile locale' char * 'che viene assegnata' in.c_str () 'per l'uso nel ciclo, e usare' in.size() 'come un contatore di cicli invece di' * in! = 0'. Oppure usa gli 'iteratori' in.begin() 'e' in.end(). –

1

Alfs suggerimento implementato in C++ 11

#include <string> 
#include <codecvt> 
#include <algorithm> 
#include <iterator> 
auto i = u8"H€llo Wørld"; 
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8; 
auto wide = utf8.from_bytes(i); 
std::string out; 
out.reserve(wide.length()); 
std::transform(wide.cbegin(), wide.cend(), std::back_inserter(out), 
      [](const wchar_t c) { return (c <= 255) ? c : '?'; }); 
// out now contains "H?llo W\xf8rld"