objective c - ¿Cómo convertir un valor unichar a un NSString en Objective-C?
unicode (5)
Tengo un personaje internacional almacenado en una variable unichar. Este personaje no proviene de un archivo o url. La variable en sí misma solo almacena un corto sin firmar (0xce91) que está en formato UTF-8 y se traduce a la letra griega mayúscula ''A''. Intento poner ese personaje en una variable NSString pero fallaré miserablemente.
He intentado de 2 maneras diferentes que fracasaron:
unichar greekAlpha = 0xce91; //could have written greekAlpha = ''Α'' instead.
NSString *theString = [NSString stringWithFormat:@"Greek Alpha: %C", greekAlpha];
No es bueno. Obtengo algunos personajes chinos extraños. Como nota al margen, esto funciona perfectamente con los personajes ingleses.
Entonces también intenté esto:
NSString *byteString = [[NSString alloc] initWithBytes:&greekAlpha
length:sizeof(unichar)
encoding:NSUTF8StringEncoding];
Pero esto tampoco funciona. Obviamente estoy haciendo algo terriblemente mal, pero no sé qué. Puede alguien ayudarme por favor ? ¡Gracias!
Aquí hay un algoritmo para la codificación UTF-8 en un solo carácter:
if (utf8char<0x80){
chars[0] = (utf8char>>0) & (0x7F | 0x00);
chars[1] = 0x00;
chars[2] = 0x00;
chars[3] = 0x00;
}
else if (utf8char<0x0800){
chars[0] = (utf8char>>6) & (0x1F | 0xC0);
chars[1] = (utf8char>>0) & (0x3F | 0x80);
chars[2] = 0x00;
chars[3] = 0x00;
}
else if (utf8char<0x010000) {
chars[0] = (utf8char>>12) & (0x0F | 0xE0);
chars[1] = (utf8char>>6) & (0x3F | 0x80);
chars[2] = (utf8char>>0) & (0x3F | 0x80);
chars[3] = 0x00;
}
else if (utf8char<0x110000) {
chars[0] = (utf8char>>18) & (0x07 | 0xF0);
chars[1] = (utf8char>>12) & (0x3F | 0x80);
chars[2] = (utf8char>>6) & (0x3F | 0x80);
chars[3] = (utf8char>>0) & (0x3F | 0x80);
}
Como 0xce91
está en formato UTF-8 y %C
espera que esté en UTF-16, una solución simple como la anterior no funcionará. Para que stringWithFormat:@"%C"
funcione, debe ingresar 0x391
que es el UTF-16 unicode.
Para crear una cadena del unichar codificado con UTF-8, primero debe dividir el Unicode en sus octetos y luego usar initWithBytes:length:encoding
.
unichar utf8char = 0xce91;
char chars[2];
int len = 1;
if (utf8char > 127) {
chars[0] = (utf8char >> 8) & (1 << 8) - 1;
chars[1] = utf8char & (1 << 8) - 1;
len = 2;
} else {
chars[0] = utf8char;
}
NSString *string = [[NSString alloc] initWithBytes:chars
length:len
encoding:NSUTF8StringEncoding];
El código anterior es el equivalente moral de unichar foo = ''abc'';
.
El problema es que ''Α''
no se asigna a un solo byte en el "conjunto de caracteres de ejecución" (supongo que UTF-8) que es "definido por la implementación" en C99 §6.4.4.4 10:
El valor de una constante de caracteres enteros que contiene más de un carácter (por ejemplo,
''ab''
) o que contiene un carácter o secuencia de escape que no se correlaciona con un carácter de ejecución de un solo byte, está definido por la implementación.
Una forma es hacer que ''ab''
igual a ''a''<<8|b
. Algunos encabezados de sistema Mac / iOS se basan en esto para cosas como OSType
/ FourCharCode
/ FourCC ; el único en iOS que me viene a la mente es el formato de píxeles CoreVideo. Esto es, sin embargo, inportable.
Si realmente quieres un literal unichar
, puedes probar L''A''
(técnicamente es un literal wchar_t
, pero en OS X e iOS, wchar_t
suele ser UTF-16, por lo que funcionará para las cosas dentro del BMP). Sin embargo, es mucho más simple usar @"Α"
(que funciona siempre que establezca la codificación de caracteres de origen correctamente) o @"/u0391"
(que ha funcionado desde al menos el iOS 3 SDK).
La respuesta anterior es excelente, pero no representa los caracteres UTF-8 de más de 16 bits, por ejemplo, el símbolo de puntos suspensivos: 0xE2,0x80,0xA6. Aquí hay un ajuste al código:
if (utf8char > 65535) {
chars[0] = (utf8char >> 16) & 255;
chars[1] = (utf8char >> 8) & 255;
chars[2] = utf8char & 255;
chars[3] = 0x00;
} else if (utf8char > 127) {
chars[0] = (utf8char >> 8) & 255;
chars[1] = utf8char & 255;
chars[2] = 0x00;
} else {
chars[0] = utf8char;
chars[1] = 0x00;
}
NSString *string = [[[NSString alloc] initWithUTF8String:chars] autorelease];
Tenga en cuenta el método de inicialización de cadena diferente que no requiere un parámetro de longitud.
unichar greekAlpha = 0x0391;
NSString* s = [NSString stringWithCharacters:&greekAlpha length:1];
Y ahora puedes incorporar ese NSString a otro de la manera que quieras. Tenga en cuenta, sin embargo, que ahora es legal escribir un alfa griego directamente en un literal NSString.