Perplesso con Unicode, Boost, C++, codecvts

In C++, voglio usare Unicode per fare le cose. Così, dopo la caduta nella tana del coniglio di Unicode, sono riuscito a finire in un treno relitto di confusione, mal di testa e locale.

Ma in Boost ho avuto la spiacevole problema di cercare di utilizzare Unicode percorsi di file e cercando di usare il Boost opzioni del programma di libreria di input Unicode. Ho letto tutto ciò che ho potuto trovare su tematiche locali, codecvts, codifiche Unicode e Spinta.

Mio tentativo di ottenere le cose a lavoro è quello di avere un codecvt che prende una stringa UTF-8 e la converte in una piattaforma di codifica UTF-8 su sistemi POSIX, UTF-16 su Windows), ho cercato di evitare wchar_t.

Il più vicino che ho effettivamente ottenuto sta cercando di fare questo con Boost.Locale, per convertire una stringa UTF-8 per un UTF-32 stringa in uscita.

#include <string>
#include <boost/locale.hpp>
#include <locale>

int main(void)
{
  std::string data("Testing, 㤹");

  std::locale fromLoc = boost::locale::generator().generate("en_US.UTF-8");
  std::locale toLoc   = boost::locale::generator().generate("en_US.UTF-32");

  typedef std::codecvt<wchar_t, char, mbstate_t> cvtType;
  cvtType const* toCvt = &std::use_facet<cvtType>(toLoc);

  std::locale convLoc = std::locale(fromLoc, toCvt);

  std::cout.imbue(convLoc);
  std::cout << data << std::endl;

  //Output is unconverted -- what?

  return 0;
}

Penso che ho avuto qualche altro tipo di conversione di lavorare con ampia caratteri, ma non so davvero cosa sto facendo. Non so cosa lo strumento giusto per il lavoro è a questo punto. Aiuto?

InformationsquelleAutor Jookia | 2011-10-22

 

3 Replies
  1. 11

    Va bene, dopo un lungo alcuni mesi ho capito, e mi piacerebbe aiutare le persone in futuro.

    Prima di tutto, il codecvt cosa era il modo sbagliato di farlo. Boost.Locale fornisce un modo semplice di convertire tra i set di caratteri nella sua boost::localizzazione::conv spazio dei nomi. Ecco un esempio (c’è gli altri non si basa sulle impostazioni internazionali).

    #include <boost/locale.hpp>
    namespace loc = boost::locale;
    
    int main(void)
    {
      loc::generator gen;
      std::locale blah = gen.generate("en_US.utf-32");
    
      std::string UTF8String = "Tésting!";
      //from_utf will also work with wide strings as it uses the character size
      //to detect the encoding.
      std::string converted = loc::conv::from_utf(UTF8String, blah);
    
      //Outputs a UTF-32 string.
      std::cout << converted << std::endl;
    
      return 0;
    }

    Come si può vedere, se si sostituisce il “it_it.utf-32” con “” sarà in uscita nel locale dell’utente.

    Ancora non so come fare std::cout fare questo tutto il tempo, ma il translate() funzione di Boost.Locale uscite nel locale dell’utente.

    Come per il filesystem usando UTF-8 corde cross platform, sembra che sia possibile, ecco un link di come fare.

    • Ecco un link che non va la pagina di indice (per l’ultimo link) boost.org/doc/libs/1_51_0/libs/locale/doc/html/…
    • Dici che utilizza codecvt è male, ma perché Boost utilizza codecvt come il metodo di conversione nel file di sistema, per l’appunto, il percorso di classe?
    • Hmm…. Ho risposto nella ’11, quindi io non sono esattamente sicuro di quello che la mia mentalità era. Suppongo che il codecvt modo che /I/ postato è stato il modo sbagliato di farlo. Boost.Locale utilizza codecvts di interfaccia con Boost.Filesystem.
  2. 3
      std::cout.imbue(convLoc);
      std::cout << data << std::endl;

    Questo non fa di conversione, dal momento che utilizza codecvt<char, char, mbstate_t> che è un no-op. L’unico standard di flussi di utilizzare codecvt sono file di streaming. std::cout non è tenuta ad effettuare alcuna conversione a tutti.

    Per forza di Spinta.Filesystem di interpretare stretta stringhe UTF-8 su windows, utilizzare boost::filesystem::infondere con un locale, con una codifica UTF-8 ↔ UTF-16 codecvt sfaccettatura. Boost.Locale ha un’implementazione di quest’ultimo.

    • Come posso fare allora?
    • Non è chiaro per me che cosa esattamente si vuole. Si sta cercando di output una stringa con sconosciuto codifica (la scrittura di un valore letterale stringa contenente caratteri unicode è già non portatile) a cout, che non hanno una tabella standard di codifica e sei libero di assumere qualsiasi codifica è. Ho sempre supporre che cout è UTF-8 e consentire all’utente di configurare la sua console per utilizzare la codifica UTF-8 o aprire il file con un editor di capire UTF-8.
    • Il mio codice non è tutto il problema, sto avendo problemi con il Boost, C++, dei locali e Unicode in generale. Voglio usare UTF-8 stringhe nel mio programma, e tradurre le impostazioni locali dell’utente da/a UTF-8, per l’uso con cout e cin, che io non riesco a capire come fare. Ma poi voglio usare UTF-8 e Spinta, che sembra essere impossibile, in quanto utilizza ampia stringhe, che non aiutano affatto.
    • Di nuovo, la tua domanda è troppo vaga: “sto avendo dei problemi … in generale”! “Voglio usare UTF-8 stringhe nel mio programma” go on! Che è quello che faccio io. “locale dell’utente da/per UTF-8 per l’uso con cout e cin” perché? Solo supporre che è UTF-8 e coloro che utilizzano eredità di codifica cambiare la loro codifica in UTF-8. Su windows si intendono utilizzare wcin e wcout di lettura/scrittura di dati unicode, ma non è portatile come avrai a mantenere due versioni del codice, che si avvale di wcout su windows e uno che utilizza cout non windows. Tu non vuoi questo, vero?
    • “Ma poi voglio usare UTF-8 e Spinta, che sembra essere impossibile” in alcune parti del boost è possibile, ma scomodo. Alcune parti di boost non supportano unicode su windows (Boost.Interprocesso), alcuni lo fanno torto (Boost.Program_Options) e alcune dolorose per codice cross-platform (Boost.Il Filesystem). “come si utilizza un’ampia stringhe” no. Alcune parti di potenziamento, uso ristretto-char (Boost.Interprocesso), alcuni usano entrambi (Boost.Il Filesystem). Il problema è che chi usa la stretta stringa di assumere la codifica nativa invece di UTF-8, per impostazione predefinita, imponendo l’onere su di voi.
    • C’è una lotta in boost comunità disprezzando i wide-char e assumendo tutte strette, stringhe UTF-8. Noi (i sostenitori di UTF-8) non sono attualmente perdere poiché non c’è molta domanda, e più spinta agli sviluppatori (ad esempio, autore di Filesystem) vivere nel mondo Unix e non di fronte al mondo reale difficoltà di scrittura di Unicode-corretto il codice di produzione portatile tra windows e linux. Se si desidera modificare lo “status quo”, aprire la discussione in boost-mailing list di nuovo.
    • Quindi dovrei cadere l’idea di Unicode e bastone con il buon ol’ ASCII, visto che non si può davvero utilizzare Unicode portabile? O forse dovrei semplicemente bastone con UNIX?
    • Perché rinunciare? Sì, non sempre è possibile farlo in modo portatile con librerie esistenti, e avete bisogno di scrivere caldaia-piastra codice di farlo con gli altri. La scelta di sostenere entro i limiti del possibile è fino a voi.
    • Mi arrendo perché non capisco quale sia il problema completamente, e che io in realtà non è possibile dedurre una possibile soluzione.

  3. 2

    La Spinta filesystem iostream sostituzione classi funzionano bene con la codifica UTF-16, quando utilizzato con Visual C++.

    Tuttavia, essi non funzionano (nel senso di sostenere arbitrario i nomi di file) quando utilizzato con g++ in Windows, almeno come di Boost versione 1.47. C’è un commento di codice spiegando che, in sostanza, il Visual C++ libreria standard fornisce non standard wchar_t a base di costruttori che Aumentare filesystem classi di ma g++ non supporta le estensioni.

    Una soluzione è utilizzare 8.3 nomi brevi, ma questa soluzione è un po ‘ fragile, dal momento che con le vecchie versioni di Windows, l’utente può disattivare la generazione automatica di nomi brevi.


    Codice di esempio per l’utilizzo di Spinta filesystem di Windows:

    #include "CmdLineArgs.h"        //CmdLineArgs
    #include "throwx.h"             //throwX, hopefully
    #include "string_conversions.h" //ansiOrFillerFrom( wstring )
    
    #include <boost/filesystem/fstream.hpp>     //boost::filesystem::ifstream
    #include <iostream>             //std::cout, std::cerr, std::endl
    #include <stdexcept>            //std::runtime_error, std::exception
    #include <string>               //std::string
    #include <stdlib.h>             //EXIT_SUCCESS, EXIT_FAILURE
    using namespace std;
    namespace bfs = boost::filesystem;
    
    inline string ansi( wstring const& ws ) { return ansiWithFillersFrom( ws ); }
    
    int main()
    {
        try
        {
            CmdLineArgs const   args;
            wstring const       programPath     = args.at( 0 );
    
            hopefully( args.nArgs() == 2 )
                || throwX( "Usage: " + ansi( programPath ) + " FILENAME" );
    
            wstring const       filePath        = args.at( 1 );
            bfs::ifstream       stream( filePath );     //Nice Boost ifstream subclass.
            hopefully( !stream.fail() )
                || throwX( "Failed to open file '" + ansi( filePath ) + "'" );
    
            string line;
            while( getline( stream, line ) )
            {
                cout << line << endl;
            }
            hopefully( stream.eof() )
                || throwX( "Failed to list contents of file '" + ansi( filePath ) + "'" );
    
            return EXIT_SUCCESS;
        }
        catch( exception const& x )
        {
            cerr << "!" << x.what() << endl;
        }
        return EXIT_FAILURE;
    }
    • Sto cercando di fare cross-platform.
    • ok. stavo supponendo che si ristretto a voi stessi di locale UTF-8 *nix (e Mac), e Windows. di supporto generale cross-platform è penso che non è qualcosa che un uomo può fare. buona fortuna!
    • Questa risposta è una dimostrazione di alcune delle mie pretese di seguito. Per utilizzare la spinta.filesystem con unicode su windows è necessario utilizzare wstring, non windows, è sicuramente desidera utilizzare stringa. Questo è come boost.filesystem non non nascondere le differenze di piattaforma e non non rendere la scrittura di codice cross-platform più semplice. Devo ammettere che, in caso di spinta.fs è possibile cambiare il modo di interpretare stretta stringhe UTF-8, in modo da semplificare la porta del codice. Tuttavia, il punto è che la spinta potrebbero rendere la nostra vita molto più facile con il solo cambio di due linee di spinta.fs. E ‘ un peccato che non vogliono.
    • nota che la spinta filesystem non supporta generale, nomi dei file con g++ in windows, e che il problema non può essere risolto utilizzando la codifica utf-8 ovunque.
    • Mi scusi, cosa vuol dire esattamente? Se è stato compilato con BOOST_POSIX_API allora, infatti, non è così. Se è stato compilato con BOOST_WINDOWS_API quindi l’unica parte che non è il boost::filesystem: mi/ofstream. Si potrebbe implementare il più tardi con l’attuazione della filebuf utilizzo di winodows direttamente con le API (questo l’ho fatto io).
    • voglio dire esattamente quello che ho scritto, che è stato abbastanza esatta. ad esempio, attualmente boost::filesystem::ifstream non riesce ad aprire un file con un nome simile [π.ricetta], quando viene utilizzato con g++. a meno che uno imposta la tabella codici ANSI a qualche tipo di codifica che supporta π, quindi, l’abbandono di alcuni altri personaggi. utilizza la codifica utf-8 non aggiustarlo. il risultato è che né la libreria standard, né boost supporta generale, nomi dei file in generale in Windows, tranne con Visual C++.
    • filesystem non supporta generale, nomi dei file” può significare, ad esempio, “boost::filesystem::remove() non supporta generale, nomi dei file” tra tutte le altre possibili interpretazioni. Adesso è chiaro. Comunque, il punto di UTF-8 non è magicamente il supporto unicode, ma piuttosto di fornire un uniforme portatile interfaccia tra i sistemi che supportano.
    • hm. penso che un “uniforme interfaccia portatile” è una buona idea, ma utf8 comune di codifica, si scontra con il principio di non pagare per quello che non è necessario o utilizzare. il nativo di codifica utilizzato, invece, dovrebbe essere svincolato dall’uniforme interfaccia portatile. comunque è prima bisogno di qualcosa che opere su tutte le piattaforme e standard filestreams non con g++ in Windows. tuttavia, una serie di wrapper come questo andare un lungo cammino verso il sostegno std flussi in Windows. è solo quando i nomi brevi sono disattivato in Windows, che non riesce. hth.,
    • Cosa stai pagando, se si assume UTF-8? Se stai parlando di conversione ad/da UTF-8, quindi dico che qualsiasi soluzione portatile che coinvolgerà un certo tipo di conversione. Questo inizia già quando C da la preferenza a stretto char contro ampia char ("" è inferiore L""). Continua quando si hanno le interfacce standardizzate, che non è possibile modificare l’API/ABI, ma può cambiare la semantica (ad esempio, l’unico modo per fare std::exception::che cosa unicode su tutte le piattaforme è quello di standardizzare essere UTF-8, o qualunque UTF che si inserisce all’interno del char su quella piattaforma).
    • Quindi, se si vuole veramente per analizzare il costo di assumere UTF-8, è necessario analizzare i modelli di utilizzo e capire dove è necessario fare le conversioni. Inoltre, non c’è nessuna tale cosa come la codifica nativa su windows. Hai due codifiche. UTF-16 e alcune deprecato non-unicode ‘ANSI’ di codifica. Inoltre, si parla sempre di boost::fs::fstreams, il che è piuttosto piccola parte di questa libreria. Il resto delle funzionalità invariato.
    • “…è prima bisogno di qualcosa che funziona su tutte le piattaforme…” non sono d’accordo. Se non funziona su una piattaforma in cui questo non può funzionare perché è impossibile, è una scusa per la demolizione, anche se rende le cose più facili su tutte le altre piattaforme?

Lascia un commento