c++ linguaggio - Converti wchar_t in char




programma pdf (7)

Tecnicamente, " char " potrebbe avere lo stesso intervallo di " signed char " o " unsigned char ". Per i caratteri non firmati, l'intervallo è corretto; in teoria, per i personaggi firmati, la tua condizione è sbagliata. In pratica, solo pochi compilatori obietteranno e il risultato sarà lo stesso.

Nitpick: l'ultimo && nell'asserzione è un errore di sintassi.

Se l'asserzione è appropriata dipende da se puoi permetterti di andare in crash quando il codice arriva al cliente, e cosa potresti o dovresti fare se la condizione di asserzione viene violata ma l'asserzione non è compilata nel codice. Per il lavoro di debug, sembra soddisfacente, ma potrebbe essere utile anche un test attivo per il controllo run-time.

Mi stavo chiedendo è sicuro di farlo?

wchar_t wide = /* something */;
assert(wide >= 0 && wide < 256 &&);
char myChar = static_cast<char>(wide);

Se sono abbastanza sicuro che l'ampio char rientrerà nell'intervallo ASCII.


assert è garantire che qualcosa sia vero in una modalità di debug, senza che abbia alcun effetto in una build di rilascio. Meglio usare un'istruzione if e avere un piano alternativo per i caratteri che non rientrano nell'intervallo, a meno che l'unico modo per ottenere caratteri al di fuori dell'intervallo sia attraverso un bug del programma.

Inoltre, a seconda della codifica dei caratteri, potresti trovare una differenza tra i caratteri Unicode da 0x80 a 0xff e la loro versione char .


Stai cercando wctomb() : è nello standard ANSI, quindi puoi contare su di esso. Funziona anche quando wchar_t usa un codice sopra 255. Quasi certamente non vuoi usarlo.

wchar_t è un tipo integrale, quindi il compilatore non si lamenterà se effettivamente lo fai:

char x = (char)wc;

ma poiché è un tipo integrale, non c'è assolutamente alcun motivo per farlo. Se accidentalmente leggi C: The Complete Reference di Herbert Schildt o qualsiasi altro libro basato su di esso, sei completamente e grossolanamente disinformato. I caratteri dovrebbero essere di tipo int o migliore . Ciò significa che dovresti scrivere questo:

int x = getchar();

e non questo:

char x = getchar(); /* <- WRONG! */

Per quanto riguarda i tipi interi, il char valore. Non dovresti creare funzioni che prendono parametri di tipo char , e non dovresti creare variabili temporanee di tipo char , e lo stesso consiglio vale anche per wchar_t .

char* può essere un typedef conveniente per una stringa di caratteri, ma è un errore da principianti considerarlo come una "serie di caratteri" o un "puntatore a una serie di caratteri" - nonostante quello che dice lo strumento cdecl . Trattandolo come una vera serie di personaggi con sciocchezze come questa:

for(int i = 0; s[i]; ++i) {
  wchar_t wc = s[i];
  char c = doit(wc);
  out[i] = c;
}

è assurdamente sbagliato. Non farà quello che vuoi; si romperà in modo sottile e serio, si comporterà in modo diverso su piattaforme diverse e sicuramente confonderai i tuoi utenti. Se lo vedi, stai cercando di reimplementare wcstombs che fa già parte di ANSI C, ma è ancora sbagliato .

Stai davvero cercando iconv() , che converte una stringa di caratteri da una codifica (anche se è impacchettata in una matrice wchar_t ), in una stringa di caratteri di un'altra codifica.

Ora leggi this , per scoprire cosa c'è di sbagliato in iconv.


Una breve funzione che ho scritto un po 'di tempo fa per confezionare un array wchar_t in un array di caratteri. I caratteri non presenti nella codepage ANSI (0-127) sono sostituiti da "?" caratteri e gestisce correttamente le coppie surrogate.

size_t to_narrow(const wchar_t * src, char * dest, size_t dest_len){
  size_t i;
  wchar_t code;

  i = 0;

  while (src[i] != '\0' && i < (dest_len - 1)){
    code = src[i];
    if (code < 128)
      dest[i] = char(code);
    else{
      dest[i] = '?';
      if (code >= 0xD800 && code <= 0xD8FF)
        // lead surrogate, skip the next code unit, which is the trail
        i++;
    }
    i++;
  }

  dest[i] = '\0';

  return i - 1;

}

si potrebbe anche convertire wchar_t -> wstring -> string -> char

wchar_t wide;
wstring wstrValue;
wstrValue[0] = wide

string strValue;
strValue.assign(wstrValue.begin(), wstrValue.end());  // convert wstring to string

char char_value = strValue[0];


Ecco una tecnica macro se vuoi qualcosa di semplice:

#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower)
#define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper)
#define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(),  ::toupper); std::transform (x.begin()+1, x.end(),   x.begin()+1,::tolower)

Tuttavia, tieni presente che il commento di @ AndreasSpindler su questa risposta è ancora una considerazione importante, tuttavia, se stai lavorando su qualcosa che non sia solo un carattere ASCII.





c++