PDA

Visualizza la versione completa : [c++] Aiuto con l'UNICODE


gila89
17-03-2013, 00:37
Salve sto cercando di creare un programma che permetta di traslitterare i nomi russi con caratteri latini. Mi sono però imbattuto in problema, il codice è il seguente:

switch(name[i])
{
case 'ш': name[i]='š'; break;
case 'ч': name[i]='č'; break;
default: break;
}

In corrispondenza delle prime due righe dello switch ho avuto il seguente warning:
warning: multi-character character constant [-Wmultichar]

Come faccio a risolvere? Se può servire sappiate che uso Code::Blocks 12.11 ed il mio sistema operativo è Ubuntu 12.04

Già che ci sono volevo segnalare un altro problema: quando uso la funzione wcout visualizzo solo punti interrogativi; ad esempio digitando wcout << L"Il risultato è ", visualizzo: Il risultato ?. Non riesco a capire dove sbaglio, ho anche controllato le impostazione di Code::Blocks e del Terminale di Gnome, in entrambi i casi risulta in uso la codica UTF-8

MItaly
17-03-2013, 03:09
Ci sono essenzialmente due possibilità.
Una è usare internamente wchar_t dovunque; 1 wchar_t = 1 codepoint Unicode (su Linux, dato che wchar_t => UCS-2; su Windows ci possono essere coppie surrogate dato che wchar_t => UTF-16), per cui lavori "normalmente" con un encoding a dimensione fissa.
Ovviamente invece di usare funzioni/classi/costrutti che operano con char usi quelle per i wchar_t :std::wstring invece di std::string, std::wcout invece di std::cout, literal wide (prima dell'apice o del doppio apice c'è una L:


wchar_t uncarattere=L'è';
const wchar_t * unastringa=L"una stringa";
)
Drawback: ogni wchar_t sono 4 byte (su Linux, 2 su Windows), per cui occupi tendenzialmente il quadruplo della memoria rispetto all'UTF-8 per testi prevalentemente con caratteri latini.

In alternativa, lavori internamente in UTF-8, che è lo standard di fatto usato per la memorizzazione/output di file Unicode su Linux; problema: l'UTF-8 è un encoding a "larghezza variabile", per cui si va da 1 a 4 char necessari per memorizzare un codepoint Unicode, e "navigare" in una stringa UTF-8 non è semplicissimo, specie perché la libreria standard C++ non fornisce nulla di seriamente utile per gestirle (anche se c'è chi tenta di rimediare (http://utfcpp.sourceforge.net/)). Per portarsi dietro stringhe Unicode senza manipolarle UTF-8 è comodo, ma per fare il mestiere che vuoi tu è pessimo.

Ergo: secondo me ti conviene lavorare con i wchar_t. In entrambi i casi, comunque, se inserisci caratteri "strani" nei sorgenti assicurati di salvarli in un encoding ben compreso dal compilatore (per g++ va più che bene UTF-8).

In ogni caso, l'argomento è molto vasto e ognuno pare avere un'idea diversa sulla questione (si va da chi dice wchar_t internamente e convertire al momento dell'IO (http://www.joelonsoftware.com/articles/Unicode.html) a chi dice di usare UTF-8 sempre (http://www.utf8everywhere.org/) a chi non raggiunge una conclusione ben definita (http://stackoverflow.com/questions/402283/stdwstring-vs-stdstring)).

gila89
17-03-2013, 03:36
OK ho capito, avrei solo altre 2 domande:
1. qual è l'opzione che devo mettere per far capire a g++ che sto lavorando con gli UNICODE?
2. una volta che ho inserito tutti i wchar_t come mi hai suggerito tu, siamo sicuri che da terminale non visualizzerò più i punti interrogativi?

MItaly
17-03-2013, 15:18
Originariamente inviato da gila89
OK ho capito, avrei solo altre 2 domande:
1. qual è l'opzione che devo mettere per far capire a g++ che sto lavorando con gli UNICODE?

Se il sorgente è in UTF-8 e usi i wchar_t come detto non dovresti fare null'altro di particolare.


2. una volta che ho inserito tutti i wchar_t come mi hai suggerito tu, siamo sicuri che da terminale non visualizzerò più i punti interrogativi?
Almeno su Linux, devi aggiungere un paio di altre cose all'inizio:


std::ios_base::sync_with_stdio(false);
std::wcout.imbue(std::locale(""));

questo fa sì che:
- le classi di IO C++ non stiano sincronizzate con stdio "classico" C, evitando così che per le conversioni da wchar_t all'encoding usato dal terminale si faccia riferimento al locale C;
- wcout usi per le conversioni il locale di default del sistema, e quindi dia in output al terminale i caratteri nell'encoding corretto (solitamente UTF8).

Dovrai fare qualcosa di simile anche per l'input (come esattamente dipende da che genere di input hai - da console, da file, che encoding usa, ...).

gila89
17-03-2013, 16:50
input da console

MItaly
18-03-2013, 01:50
Allora stessa cosa con wcin:


std::wcin.imbue(std::locale(""));

gila89
18-03-2013, 11:15
OK allora provo ad inserire queste righe di codice e vediamo come va.

Loading