2012-02-28 20 views
10

Me he dado cuenta de que el método de longitud de std :: string devuelve la longitud en bytes y el mismo método en std :: u16string devuelve el número de secuencias de 2 bytes.Con C++ 11, ¿todavía necesito una biblioteca de manipulación de cadenas no estándar para texto Unicode?

También he notado que cuando un personaje o punto de código se encuentra fuera de la BMP, longitud devuelve 4 en lugar de 2.

Por otra parte, la secuencia de escape Unicode se limita a \ unnnn, por lo que cualquier punto de código anterior U + FFFF no puede ser insertado por una secuencia de escape.

En otras palabras, no parece haber soporte para pares de sustitución o puntos de código fuera del BMP.

Dado esto, ¿es la práctica recomendada o aceptada utilizar una biblioteca de manipulación de cadenas no estándar que comprenda UTF-8, UTF-16, pares de sustitución, etc.?

¿Mi compilador tiene un error o estoy utilizando los métodos estándar de manipulación de cadenas incorrectamente?

Ejemplo:

/* 
* Example with the Unicode code points U+0041, U+4061, U+10196 and U+10197 
*/ 

#include <iostream> 
#include <string> 

int main(int argc, char* argv[]) 
{ 
    std::string example1 = u8"A䁡"; 
    std::u16string example2 = u"A䁡"; 

    std::cout << "Escape Example: " << "\u0041\u4061\u10196\u10197" << "\n"; 
    std::cout << "Example: " << example1 << "\n"; 
    std::cout << "std::string Example length: " << example1.length() << "\n"; 
    std::cout << "std::u16string Example length: " << example2.length() << "\n"; 

    return 0; 
} 

Este es el resultado que obtengo cuando compilado con GCC 4.7:

Escape Example: A䁡မ6မ7 
Example: A䁡 
std::string Example length: 12 
std::u16string Example length: 6 

Respuesta

6

A riesgo de juzgar antes de tiempo, me parece que el lenguaje utilizado en las normas en poco ambigua (aunque la conclusión final es clara, ver al final):

En la descripción de los literales char16_t (es decir, los u"..." aquellos como en su ejemplo), el tamaño de un literal se define como:

el tamaño de una cadena char16_t literal es el número total de secuencias de escape, en caracteres universal-nombres, y otros caracteres, más uno para cada personaje que requiera un par suplente, más uno para el finalizador u '\ 0'.

y la nota aclara además:

[Nota: El tamaño de una cadena char16_t literal es el número de unidades de código, no el número de caracteres. nota -fin]

Esto implica una definición de carácter y código de la unidad. Un par sustituto es un carácter, pero dos unidades de código.

Sin embargo, la descripción del método de std::basic_string (de los cuales se deriva std::u16string) length() afirma:

devuelve el número de caracteres en la cadena, es decir, std :: distancia (BEGIN(), el extremo ()). Es lo mismo que size().

Tal y como aparece, la descripción de length() utiliza la palabra carácter en el sentido de lo que la definición de char16_t llama a una unidad de código .

Sin embargo, la conclusión de todo esto es: La longitud se define como unidades de código, por lo tanto su compilador cumple con la norma, y ​​habrá demanda continua de bibliotecas especiales para proporcionar el conteo adecuado de caracteres.

I utilizaron las referencias siguientes:

  • Para la definición del tamaño de literales char16_t: Here
  • Para la descripción de std::basic_string::length(): Here
+1

Gracias por la respuesta. También estoy interesado en otros métodos de manipulación de cadenas como substr y cómo manejan UTF-8, UTF-16, pares de sustitución, etc. Debería haber sido más claro. Utilicé la longitud porque era el ejemplo más fácil de publicar. –

+0

@Ragsdale 30 cal Derecha. Supongo que tendremos que aceptar que todos estos métodos operan en unidades de código, no en caracteres, a pesar de las descripciones algo engañosas. Los iteradores son otro buen ejemplo. – jogojapan

+0

Entonces, en otras palabras, ¿la única manera estándar de trabajar con Unicode es convertir texto a UTF-32 y usar std :: u32string? Eso parece un desperdicio. –

9

std::basic_string es la unidad de código orientado, no carácter orientado. Si necesita tratar con puntos de código, puede convertir a char32_t, pero todavía no hay nada en el estándar para una funcionalidad Unicode más avanzada.

También puede usar la secuencia de escape \UNNNNNNNN para puntos de código que no sean BMP, además de escribirlos directamente (suponiendo que está utilizando una codificación de origen que los admita).

Dependiendo de sus necesidades, esto puede ser todo el soporte Unicode que necesita. Una gran cantidad de software no necesita hacer más que manipulaciones básicas de cadenas, como las que se pueden hacer fácilmente en unidades de código directamente. Para necesidades de un nivel ligeramente superior, puede convertir unidades de código en puntos de código y trabajar en ellos. Para necesidades de nivel superior, como trabajar en clústeres de grafemas, se necesitará soporte adicional.

Yo diría que esto significa que hay soporte adecuado en el estándar para representar datos Unicode y realizar una manipulación básica. Cualquier biblioteca de terceros que se use para una funcionalidad de nivel superior debería basarse en la biblioteca estándar. Conforme pasa el tiempo, es probable que el estándar también incluya más de esa funcionalidad de nivel superior.

0

Dado esto, es el ¿Práctica aceptada o recomendada para utilizar una biblioteca de manipulación de cadenas no estándar que comprende UTF-8, UTF-16, pares de sustitución, etc.?

Es difícil hablar de la práctica recomendada para un estándar de idioma que se creó hace unos meses y aún no está completamente implementado, pero en general estoy de acuerdo: la configuración regional y Unicode en C++ 11 son todavía irremediablemente inadecuado (aunque obviamente mejoraron mucho), y para un trabajo serio, debe soltarlos y usar ICU o Boost.Locale en su lugar.

La incorporación de cadenas Unicode y funciones de conversión a C++ 11 es el primer paso hacia la compatibilidad real con Unicode; el tiempo dirá si resultan útiles o si serán olvidados.

Cuestiones relacionadas