2012-02-26 28 views
5

Ho un semplice programma che verifica la conversione tra wchar_t e char usando una serie di impostazioni locali passate ad essa sulla riga di comando. Emette un elenco delle conversioni che falliscono stampando il nome della locale e la stringa che non è riuscita a convertire.xlocale rotto su OS X?

Lo sto costruendo usando clang e libC++. La mia comprensione è che il supporto locale di libC++ è fornito dalla libreria xlocale su OS X.

Sto riscontrando alcuni errori imprevisti, così come alcuni casi in cui la conversione dovrebbe fallire, ma non lo fa.

Ecco il programma.

#warning call this program like: "locale -a | ./a.out" or pass \ 
locale names valid for your platform, one per line via standard input 

#include <iostream> 
#include <codecvt> 
#include <locale> 
#include <array> 

template <class Facet> 
class usable_facet : public Facet { 
public: 
    // FIXME: use inheriting constructors when available 
    // using Facet::Facet; 
    template <class ...Args> 
    usable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {} 
    ~usable_facet() {} 
}; 

int main() { 
    std::array<std::wstring,11> args = {L"a",L"é",L"¤",L"€",L"Да",L"Ψ",L"א",L"আ",L"✈",L"가",L""}; 

    std::wstring_convert<usable_facet<std::codecvt_utf8<wchar_t>>> u8cvt; // wchar_t uses UCS-4/UTF-32 on this platform 

    int convert_failures = 0; 
    std::string line; 
    while(std::getline(std::cin,line)) { 
     if(line.empty()) 
      continue; 

     using codecvt = usable_facet<std::codecvt_byname<wchar_t,char,std::mbstate_t>>; 
     std::wstring_convert<codecvt> convert(new codecvt(line)); 

     for(auto const &s : args) { 
      try { 
       convert.to_bytes(s); 
      } catch (std::range_error &e) { 
       convert_failures++; 
       std::cout << line << " : " << u8cvt.to_bytes(s) << '\n'; 
      } 
     } 
    } 

    std::cout << std::string(80,'=') << '\n'; 
    std::cout << convert_failures << " wstring_convert to_bytes failures.\n"; 
} 

Ecco alcuni esempi di uscita corretta

en_US.ISO8859-1 : € 
en_US.US-ASCII : ✈ 

Ecco un esempio di output che non è previsto

en_US.ISO8859-15 : € 

Il carattere dell'euro esiste nella norma ISO 8859-15 charset e quindi questo non dovrebbe fallire.

Ecco alcuni esempi di uscita che mi aspetto, ma non ricevo

en_US.ISO8859-15 : ¤ 
en_US.US-ASCII : ¤ 

Questo è il simbolo di valuta che esiste nella norma ISO 8859-1, ma è stato rimosso e sostituito con il simbolo dell'euro nella norma ISO 8859-15. Questa conversione non dovrebbe avere successo, ma nessun errore viene segnalato. Esaminando ulteriormente questo caso, trovo che in entrambi i casi "¤" viene convertito in 0xA4, che è la rappresentazione ISO 8859-1 di "¤".

Non sto usando xlocale direttamente, solo indirettamente tramite libC++. Xlocale su Mac OS X è semplicemente rotto con definizioni locali errate? C'è un modo per risolverlo? O i problemi che sto vedendo sono il risultato di qualcos'altro?

risposta

3

Ho il sospetto che si stiano riscontrando problemi con il sistema xlocale. Un bug report sarebbe più apprezzato!

+2

terminato. id 10935025 – bames53

+0

Sembra ancora rotto in 10.8 :(Forse c'è un modo per ottenere i dati xlocale e hackerare una correzione manualmente? – bames53

+0

Si scopre che UTF-32 non è in effetti utilizzato come codifica wchar_t da tutte le impostazioni locali su OS X – bames53

-1

Non so perché ci si aspetta che wchar_t sia UTF-32 o dove si è sentito che "la convenzione di OS X che wchar_t è UTF-32". Questo è certamente sbagliato. wchar_t ha solo 16 bit di larghezza.

Vedere http://en.wikipedia.org/wiki/Wide_character per ulteriori informazioni su wchar_t.

+3

'wchar_t' è largo 32 bit su OS X e la maggior parte dei sistemi operativi unix, non 16. – bames53

+1

... un fatto che Wikipedia menziona, oltre al fatto che potrebbe anche essere 8 bit su altre piattaforme. +11 aggiunge 'char16_t' e' char32_t' per risolvere questo problema, ma questo non è correlato. – Potatoswatter