No puedo entender las diferencias entre std::string
y std::wstring
. Sé que wstring
admite caracteres anchos, como los caracteres Unicode. Tengo las siguientes preguntas:
- ¿Cuándo debo usar
std::wstring
másstd::string
? - ¿Puede
std::string
contener todo el conjunto de caracteres ASCII, incluidos los caracteres especiales? - ¿Es
std::wstring
compatible con todos los compiladores de C ++ populares? - ¿Qué es exactamente un " personaje ancho "?
Respuestas:
string
?wstring
?std::string
es unabasic_string
plantilla en unchar
, ystd::wstring
en unwchar_t
.char
vs.wchar_t
char
se supone que tiene un carácter, generalmente un carácter de 8 bits.wchar_t
se supone que tiene un carácter ancho, y luego, las cosas se ponen difíciles:en Linux, a
wchar_t
es de 4 bytes, mientras que en Windows es de 2 bytes.¿Qué pasa con Unicode , entonces?
El problema es que ni
char
tampocowchar_t
está directamente vinculado a Unicode.En Linux?
Tomemos un sistema operativo Linux: mi sistema Ubuntu ya es compatible con Unicode. Cuando trabajo con una cadena de caracteres, está codificada de forma nativa en UTF-8 (es decir, cadena de caracteres Unicode). El siguiente código:
genera el siguiente texto:
Verá que el texto "olé"
char
está realmente construido por cuatro caracteres: 110, 108, 195 y 169 (sin contar el cero final). (Te dejaré estudiar elwchar_t
código como ejercicio)Entonces, cuando trabajas con un
char
sistema operativo en Linux, generalmente debes terminar usando Unicode sin siquiera saberlo. Y comostd::string
funcionachar
,std::string
ya está listo para Unicode.Tenga en cuenta que
std::string
, al igual que la API de cadena C, considerará que la cadena "olé" tiene 4 caracteres, no tres. Por lo tanto, debe tener cuidado al truncar / jugar con caracteres unicode porque está prohibida alguna combinación de caracteres en UTF-8.En Windows
En Windows, esto es un poco diferente. Win32 tuvo que soportar una gran cantidad de aplicaciones trabajando con
char
y en diferentes charsets / páginas de códigos producidos en todo el mundo, antes del advenimiento de Unicode.Por lo tanto, su solución fue interesante: si una aplicación funciona
char
, las cadenas de caracteres se codifican / imprimen / muestran en las etiquetas de la GUI utilizando el juego de caracteres / página de códigos local en la máquina. Por ejemplo, "olé" sería "olé" en un Windows localizado en francés, pero sería algo diferente en un Windows cirílico ("olé" si usa Windows-1251 ). Por lo tanto, las "aplicaciones históricas" generalmente seguirán funcionando de la misma manera.Para las aplicaciones basadas en Unicode, Windows usa
wchar_t
, que tiene 2 bytes de ancho, y está codificado en UTF-16 , que está codificado en Unicode en caracteres de 2 bytes (o al menos, el UCS-2 en su mayoría compatible, que es casi el lo mismo IIRC).Las aplicaciones que usan
char
se dicen "multibyte" (porque cada glifo está compuesto por uno o máschar
s), mientras que las aplicaciones que usanwchar_t
se dicen "widechar" (porque cada glifo está compuesto por uno o doswchar_t
. Consulte MultiByteToWideChar y WideCharToMultiByte Win32 API de conversión para obtener más información.Por lo tanto, si trabaja en Windows, desea usarlo
wchar_t
(a menos que use un marco que lo oculte, como GTK + o QT ...). El hecho es que detrás de escena, Windows trabaja conwchar_t
cadenas, por lo que incluso las aplicaciones históricas tendrán suschar
cadenas convertidaswchar_t
cuando usen API comoSetWindowText()
(función API de bajo nivel para establecer la etiqueta en una GUI Win32).Problemas de memoria?
UTF-32 es de 4 bytes por caracteres, por lo que no hay mucho que agregar, solo si un texto UTF-8 y un texto UTF-16 siempre usarán menos o la misma cantidad de memoria que un texto UTF-32 (y generalmente menos )
Si hay un problema de memoria, debe saber que para la mayoría de los idiomas occidentales, el texto UTF-8 usará menos memoria que el mismo UTF-16.
Aún así, para otros idiomas (chino, japonés, etc.), la memoria utilizada será la misma o ligeramente mayor para UTF-8 que para UTF-16.
Con todo, UTF-16 utilizará principalmente 2 y ocasionalmente 4 bytes por carácter (a menos que se trate de algún tipo de glifos de lenguaje esotérico (Klingon? Élfico?), Mientras que UTF-8 gastará de 1 a 4 bytes.
Ver http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 para más información.
Conclusión
¿Cuándo debería usar std :: wstring sobre std :: string?
En Linux? Casi nunca (§).
En Windows Casi siempre (§).
¿En código multiplataforma? Depende de su kit de herramientas ...
(§): a menos que utilice un kit de herramientas / marco que indique lo contrario
¿Puede
std::string
contener todo el conjunto de caracteres ASCII, incluidos los caracteres especiales?Aviso: A
std::string
es adecuado para mantener un búfer 'binario', donde unstd::wstring
no lo es!En Linux? Si.
En Windows Solo caracteres especiales disponibles para la configuración regional actual del usuario de Windows.
Editar (después de un comentario de Johann Gerell ):
a
std::string
será suficiente para manejar todas laschar
cadenas de base (cadachar
una con un número del 0 al 255). Pero:char
NO son ASCII.char
de 0 a 127 se mantendrá correctamentechar
de 128 a 255 tendrá un significado dependiendo de su codificación (unicode, no unicode, etc.), pero podrá contener todos los glifos Unicode siempre que estén codificados en UTF-8.¿Es
std::wstring
compatible con casi todos los compiladores de C ++ populares?Principalmente, con la excepción de los compiladores basados en GCC que se portan a Windows.
Funciona en mi g ++ 4.3.2 (bajo Linux), y utilicé la API Unicode en Win32 desde Visual C ++ 6.
¿Qué es exactamente un personaje ancho?
En C / C ++, es un tipo de carácter escrito
wchar_t
que es más grande que elchar
tipo de carácter simple . Se supone que se usa para poner dentro de caracteres cuyos índices (como los glifos Unicode) son mayores que 255 (o 127, dependiendo ...).fuente
olè
está codificado como UTF-8 o no. Más aún, la razón por la que no se puede de forma nativa transmitirwchar_t *
astd::cout
se debe a que los tipos son incompatibles resultando en un programa mal formada y no tiene nada que ver con el uso de codificaciones. Vale la pena señalar que si usastd::string
ostd::wstring
depende de su propia preferencia de codificación en lugar de la plataforma, especialmente si desea que su código sea portátil.std::wstring
debería usarse en Windows porque es una mejor opción para la API de Windows Unicode, que creo que es falaz. Si su única preocupación era llamar a la API de Windows Unicode y no ordenar cadenas, entonces seguro, pero no compro esto como el caso general.If your only concern was calling into the Unicode Windows API and not marshalling strings then sure
Entonces, estamos de acuerdo. Estoy codificando en C ++, no en JavaScript. Evitar la clasificación inútil o cualquier otro procesamiento potencialmente costoso en tiempo de ejecución cuando se puede hacer en tiempo de compilación es la esencia de ese lenguaje. La codificación contra WinAPI y el usostd::string
es solo una pérdida injustificada de recursos en tiempo de ejecución. Lo encuentras falaz, y está bien, ya que es tu punto de vista. La mía es que no escribiré código con pesimismo en Windows solo porque se ve mejor desde el lado de Linux.Recomiendo evitar
std::wstring
en Windows o en otro lugar, excepto cuando lo requiera la interfaz, o en cualquier lugar cerca de las llamadas API de Windows y las conversiones de codificación respectivas como un azúcar sintáctico.Mi punto de vista se resume en http://utf8everywhere.org del cual soy coautor.
A menos que su aplicación esté centrada en llamadas de API, por ejemplo, principalmente en aplicaciones de IU, la sugerencia es almacenar cadenas Unicode en std :: string y codificadas en UTF-8, realizando conversiones cerca de llamadas API. Los beneficios descritos en el artículo superan la aparente molestia de la conversión, especialmente en aplicaciones complejas. Esto es doble para el desarrollo de múltiples plataformas y bibliotecas.
Y ahora, respondiendo tus preguntas:
fuente
Entonces, cada lector aquí ahora debe tener una comprensión clara sobre los hechos, la situación. Si no, entonces debe leer la respuesta extraordinariamente completa de paercebal [por cierto: ¡gracias!].
Mi conclusión pragmática es sorprendentemente simple: todo ese material de "codificación de caracteres" de C ++ (y STL) está sustancialmente roto e inútil. Echarle la culpa a Microsoft o no, eso no ayudará de todos modos.
Mi solución, después de una investigación en profundidad, mucha frustración y las experiencias consecuentes es la siguiente:
acepta que tienes que ser responsable por ti mismo de las cosas de codificación y conversión (y verás que gran parte es bastante trivial)
use std :: string para cualquier cadena codificada UTF-8 (solo a
typedef std::string UTF8String
)acepte que dicho objeto UTF8String es solo un contenedor tonto, pero barato. Nunca acceda y / o manipule caracteres directamente en él (sin búsqueda, reemplazo, etc.). ¡Podría, pero realmente no quiere perder el tiempo escribiendo algoritmos de manipulación de texto para cadenas de varios bytes! Incluso si otras personas ya hicieron cosas tan estúpidas, ¡no hagas eso! ¡Déjalo ser! (Bueno, hay escenarios en los que tiene sentido ... solo use la biblioteca de la UCI para esos).
use std :: wstring para cadenas codificadas UCS-2 (
typedef std::wstring UCS2String
): esto es un compromiso y una concesión al desorden que introdujo la API WIN32). UCS-2 es suficiente para la mayoría de nosotros (más sobre eso más adelante ...).use instancias UCS2String siempre que se requiera un acceso carácter por carácter (lectura, manipulación, etc.). Cualquier procesamiento basado en caracteres debe hacerse en una representación NO multibyte. Es simple, rápido, fácil.
agregue dos funciones de utilidad para convertir de ida y vuelta entre UTF-8 y UCS-2:
Las conversiones son sencillas, Google debería ayudar aquí ...
Eso es. Utilice UTF8String donde la memoria sea valiosa y para todas las E / S UTF-8. Utilice UCS2String donde la cadena debe analizarse y / o manipularse. Puede convertir entre esas dos representaciones en cualquier momento.
Alternativas y mejoras
Las conversiones desde y hacia codificaciones de caracteres de un solo byte (por ejemplo, ISO-8859-1) se pueden realizar con la ayuda de tablas de traducción simples, por ejemplo,
const wchar_t tt_iso88951[256] = {0,1,2,...};
y el código apropiado para la conversión hacia y desde UCS2.si UCS-2 no es suficiente, entonces cambie a UCS-4 (
typedef std::basic_string<uint32_t> UCS2String
)UCI u otras bibliotecas Unicode?
Para cosas avanzadas.
fuente
Cuando desee tener caracteres anchos almacenados en su cadena.
wide
Depende de la implementación. Visual C ++ por defecto es de 16 bits si no recuerdo mal, mientras que GCC por defecto depende del objetivo. Tiene 32 bits de largo aquí. Tenga en cuenta que wchar_t (tipo de carácter ancho) no tiene nada que ver con unicode. Simplemente se garantiza que puede almacenar todos los miembros del juego de caracteres más grande que la implementación admite en sus configuraciones regionales, y al menos mientras char. También puede almacenar cadenas Unicode parastd::string
usar lautf-8
codificación. Pero no entenderá el significado de los puntos de código Unicode. Entoncesstr.size()
no le dará la cantidad de caracteres lógicos en su cadena, sino simplemente la cantidad de elementos char o wchar_t almacenados en esa cadena / wstring. Por esa razón, la gente del envoltorio gtk / glib C ++ ha desarrollado unaGlib::ustring
clase que puede manejar utf-8.Si su wchar_t tiene 32 bits de largo, puede usarlo
utf-32
como codificación unicode, y puede almacenar y manejar cadenas unicode usando una codificación fija (utf-32 es de longitud fija). Esto significa de su wstrings.size()
función será entonces devolver la cantidad correcta de elementos wchar_t y caracteres lógicos.fuente
std::wstring
.Con frecuencia uso std :: string para contener caracteres utf-8 sin ningún problema. Recomiendo encarecidamente hacer esto al interactuar con API que usan utf-8 como el tipo de cadena nativo también.
Por ejemplo, uso utf-8 cuando interactúo mi código con el intérprete Tcl.
La advertencia principal es la longitud de la cadena std ::, ya no es el número de caracteres en la cadena.
fuente
fuente
fuente
Las aplicaciones que no están satisfechas con solo 256 caracteres diferentes tienen la opción de usar caracteres anchos (más de 8 bits) o una codificación de longitud variable (una codificación multibyte en terminología C ++) como UTF-8. Los caracteres anchos generalmente requieren más espacio que una codificación de longitud variable, pero son más rápidos de procesar. Las aplicaciones en varios idiomas que procesan grandes cantidades de texto generalmente usan caracteres anchos cuando procesan el texto, pero lo convierten a UTF-8 cuando lo almacenan en el disco.
La única diferencia entre ay
string
awstring
es el tipo de datos de los caracteres que almacenan. Una cadena almacenachar
s cuyo tamaño está garantizado en al menos 8 bits, por lo que puede usar cadenas para procesar, por ejemplo, texto ASCII, ISO-8859-15 o UTF-8. El estándar no dice nada sobre el conjunto de caracteres o la codificación.Prácticamente todos los compiladores usan un juego de caracteres cuyos primeros 128 caracteres corresponden con ASCII. Este es también el caso de los compiladores que usan codificación UTF-8. Lo importante a tener en cuenta al usar cadenas en UTF-8 o alguna otra codificación de longitud variable, es que los índices y las longitudes se miden en bytes, no en caracteres.
El tipo de datos de una wstring es
wchar_t
, cuyo tamaño no está definido en el estándar, excepto que tiene que ser al menos tan grande como un carácter, generalmente 16 bits o 32 bits. wstring se puede utilizar para procesar texto en la codificación de caracteres anchos definida por la implementación. Debido a que la codificación no está definida en el estándar, no es sencillo convertir entre cadenas y wstrings. Tampoco se puede suponer que wstrings tenga una codificación de longitud fija.Si no necesita soporte en varios idiomas, puede usar solo cadenas regulares. Por otro lado, si está escribiendo una aplicación gráfica, a menudo es el caso de que la API solo admite caracteres anchos. Entonces, probablemente desee utilizar los mismos caracteres anchos al procesar el texto. Tenga en cuenta que UTF-16 es una codificación de longitud variable, lo que significa que no puede asumir
length()
que devuelve el número de caracteres. Si la API utiliza una codificación de longitud fija, como UCS-2, el procesamiento se vuelve fácil. La conversión entre caracteres anchos y UTF-8 es difícil de hacer de forma portátil, pero, una vez más, su API de interfaz de usuario probablemente sea compatible con la conversión.fuente
Una buena pregunta! Creo que la CODIFICACIÓN DE DATOS (a veces un CHARSET también involucrado) es un MECANISMO DE EXPRESIÓN DE MEMORIA para guardar datos en un archivo o transferir datos a través de una red, por lo que respondo esta pregunta como:
1. ¿Cuándo debo usar std :: wstring sobre std :: string?
Si la plataforma de programación o la función API es de un solo byte, y deseamos procesar o analizar algunos datos Unicode, por ejemplo, leer desde el archivo Windows'.REG o la transmisión de red de 2 bytes, deberíamos declarar la variable std :: wstring fácilmente procesarlos por ejemplo: wstring ws = L "中国 a" (memoria de 6 octetos: 0x4E2D 0x56FD 0x0061), podemos usar ws [0] para obtener el carácter '中' y ws [1] para obtener el carácter '国' y ws [2] a obtener el carácter 'a', etc.
2. ¿Puede std :: string contener todo el conjunto de caracteres ASCII, incluidos los caracteres especiales?
Si. Pero tenga en cuenta: ASCII estadounidense, significa que cada octeto 0x00 ~ 0xFF representa un carácter, incluido el texto imprimible como "123abc & * _ &" y usted dijo que uno especial, en su mayoría lo imprime como '.' evite confundir editores o terminales. Y algunos otros países extienden su propio juego de caracteres "ASCII", por ejemplo, chino, usan 2 octetos para representar un carácter.
3. ¿Es std :: wstring compatible con todos los compiladores de C ++ populares?
Quizás, o mayormente. He usado: VC ++ 6 y GCC 3.3, SÍ
4. ¿Qué es exactamente un "personaje ancho"?
un carácter ancho indica principalmente el uso de 2 octetos o 4 octetos para contener los caracteres de todos los países. 2 octetos UCS2 es una muestra representativa y, por ejemplo, en inglés 'a', su memoria es de 2 octetos de 0x0061 (en comparación con ASCII 'la memoria de a es de 1 octeto 0x61)
fuente
Aquí hay algunas respuestas muy buenas, pero creo que hay un par de cosas que puedo agregar con respecto a Windows / Visual Studio. Esto se basa en mi experiencia con VS2015. En Linux, básicamente la respuesta es usar UTF-8 codificado en
std::string
todas partes. En Windows / VS se vuelve más complejo. Aquí es por qué. Windows espera que las cadenas almacenadas conchar
s se codifiquen con la página de códigos de configuración regional. Este es casi siempre el conjunto de caracteres ASCII seguido de otros 128 caracteres especiales dependiendo de su ubicación. Permítanme decir que esto no solo cuando se usa la API de Windows, hay otros tres lugares importantes donde estas cadenas interactúan con C ++ estándar. Estos son literales de cadena, enviados astd::cout
usar<<
y pasando un nombre de archivo astd::fstream
.Aquí voy a decir que soy programador, no especialista en idiomas. Aprecio que USC2 y UTF-16 no sean lo mismo, pero para mis propósitos están lo suficientemente cerca como para ser intercambiables y los uso como tales aquí. En realidad, no estoy seguro de qué Windows usa, pero generalmente tampoco necesito saberlo. He dicho UCS2 en esta respuesta, lo siento de antemano si molesto a alguien con mi ignorancia de este asunto y estoy feliz de cambiarlo si tengo algo mal.
Literales de cadena
Si ingresa literales de cadena que contienen solo caracteres que pueden ser representados por su página de códigos, entonces VS los almacena en su archivo con 1 byte por codificación de caracteres basado en su página de códigos. Tenga en cuenta que si cambia su página de códigos o le da su fuente a otro desarrollador usando una página de códigos diferente, entonces creo (pero no lo he probado) que el personaje terminará siendo diferente. Si ejecuta su código en una computadora usando una página de códigos diferente, entonces no estoy seguro de si el carácter también cambiará.
Si ingresa algún literal de cadena que no pueda ser representado por su página de códigos, VS le pedirá que guarde el archivo como Unicode. El archivo se codificará como UTF-8. Esto significa que todos los caracteres no ASCII (incluidos los que están en su página de códigos) estarán representados por 2 o más bytes. Esto significa que si le das tu fuente a otra persona, la fuente se verá igual. Sin embargo, antes de pasar la fuente al compilador, VS convierte el texto codificado UTF-8 en texto codificado en la página de códigos y los caracteres que faltan en la página de códigos se reemplazan con
?
.La única forma de garantizar la representación correcta de un literal de cadena Unicode en VS es preceder al literal de cadena con un
L
literal de cadena ancha. En este caso, VS convertirá el texto codificado UTF-8 del archivo a UCS2. Luego debe pasar este literal de cadena a unstd::wstring
constructor o debe convertirlo a utf-8 y ponerlo en astd::string
. O si lo desea, puede usar las funciones de la API de Windows para codificarlo usando su página de códigos para ponerlo en unstd::string
, pero es posible que tampoco haya usado un literal de cadena ancha.std :: cout
Cuando salga a la consola usando
<<
solo puede usarstd::string
, no,std::wstring
y el texto debe codificarse usando su página de códigos de configuración regional. Si tiene unstd::wstring
archivo, debe convertirlo usando una de las funciones de la API de Windows y los caracteres que no estén en su página de códigos serán reemplazados por?
(tal vez pueda cambiar el carácter, no recuerdo).std :: nombres de archivos fstream
El sistema operativo Windows usa UCS2 / UTF-16 para sus nombres de archivo, por lo que sea cual sea su página de códigos, puede tener archivos con cualquier carácter Unicode. Pero esto significa que para acceder o crear archivos con caracteres que no están en su página de códigos debe usar
std::wstring
. No hay otra manera. Esta es una extensión específica de Microsoft parastd::fstream
que probablemente no se compile en otros sistemas. Si usa std :: string, solo puede utilizar nombres de archivo que solo incluyan caracteres en su página de códigos.Sus opciones
Si solo está trabajando en Linux, probablemente no haya llegado tan lejos. Simplemente use UTF-8 en
std::string
todas partes.Si solo está trabajando en Windows, use UCS2 en
std::wstring
todas partes. Algunos puristas pueden decir que use UTF8 y luego convierta cuando sea necesario, pero ¿por qué molestarse con la molestia?Si eres multiplataforma, es un desastre ser sincero. Si intenta usar UTF-8 en todas partes en Windows, entonces debe tener mucho cuidado con los literales de cadena y la salida a la consola. Puede corromper fácilmente sus cadenas allí. Si usa
std::wstring
todas partes en Linux, es posible que no tenga acceso a la versión amplia destd::fstream
, por lo que debe hacer la conversión, pero no hay riesgo de corrupción. Así que personalmente creo que esta es una mejor opción. Muchos no estarían de acuerdo, pero no estoy solo: es el camino tomado por wxWidgets, por ejemplo.Otra opción podría ser typedef
unicodestring
comostd::string
en Linux ystd::wstring
en Windows, y tienen una macro llamada UNI () que prefija L en Windows y en Linux nada, entonces el códigoestaría bien en cualquier plataforma, creo.
Respuestas
Entonces para responder a sus preguntas
1) Si está programando para Windows, todo el tiempo, si es multiplataforma, tal vez todo el tiempo, a menos que desee lidiar con posibles problemas de corrupción en Windows o escribir algún código con plataforma específica
#ifdefs
para solucionar las diferencias, si solo usa Linux entonces nunca.2) sí. Además en Linux, también puede usarlo para todos los Unicode. En Windows, solo puede usarlo para todos los Unicode si elige codificar manualmente con UTF-8. Pero la API de Windows y las clases estándar de C ++ esperarán
std::string
que se codifique utilizando la página de códigos de la configuración regional. Esto incluye todos los ASCII más otros 128 caracteres que cambian dependiendo de la página de códigos que su computadora esté configurada para usar.3) Creo que sí, pero si no, es solo un simple typedef de 'std :: basic_string' usando en
wchar_t
lugar dechar
4) Un carácter ancho es un tipo de carácter que es más grande que el
char
tipo estándar de 1 byte . En Windows es de 2 bytes, en Linux es de 4 bytes.fuente
/utf-8
).1) Como mencionó Greg, wstring es útil para la internacionalización, es cuando lanzará su producto en otros idiomas además del inglés
4) Mira esto para ver los caracteres anchos http://en.wikipedia.org/wiki/Wide_character
fuente
¿Cuándo NO deberías usar caracteres anchos?
Cuando escribes código antes del año 1990.
Obviamente, estoy siendo flip, pero realmente, es el siglo XXI ahora. 127 personajes han dejado de ser suficientes desde hace mucho tiempo. Sí, puede usar UTF8, pero ¿por qué molestarse con los dolores de cabeza?
fuente
wchar_t
es que su tamaño y significado son específicos del sistema operativo. Simplemente intercambia los viejos problemas con los nuevos. Mientras que achar
es unchar
sistema operativo independiente (al menos en plataformas similares). Por lo tanto, también podríamos usar UTF-8, empaquetar todo en secuencias dechar
s y lamentar cómo C ++ nos deja completamente solos sin ningún método estándar para medir, indexar, encontrar, etc., dentro de tales secuencias.wchar_t
es un tipo de datos de ancho fijo, por lo que una matriz de 10wchar_t
siempre ocuparásizeof(wchar_t) * 10
bytes de la plataforma. Y UTF-16 es una codificación de ancho variable en la que los caracteres pueden estar formados por 1 o 2 puntos de código de 16 bits (y s / 16/8 / g para UTF-8).