Una función C ++ para leer puntos de código de un flujo UTF-8 -- ++ campo con utf-8 camp codereview Relacionados El problema

A C++ function to read Code Points from an UTF-8 Stream


2
vote

problema

Español

He escrito una función que lee y devuelve un punto de código UTF-8 desde un isttream. Me pregunto si el código es eficiente o si hay algunos problemas obvios con la implementación.

  Employee5  
Original en ingles

I've written a function that reads and returns one UTF-8 code point from an istream. I am wondering if the code is efficient or if there are some obvious problems with the implementation.

chr_t utf32::get_utf32_char(std::istream &in_stream) {     int next;     chr_t out = in_stream.get();     if (out == -1 || out < 0x80) {         return out;     } else if ((out & 0xe0) == 0xc0) {         out &= 0x1f;         out <<= 6;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= next & 0x3F;         return out;     } else if ((out & 0xf0) == 0xe0) {         out &= 0x0f;         out <<= 12;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= (next & 0x3F) << 6;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= next & 0x3F;         return out;     } else if ((out & 0xf8) == 0xf0) {         out &= 0x07;         out <<= 18;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= (next & 0x3F) << 12;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= (next & 0x3F) << 6;         next = in_stream.get();         if (next == -1) goto invalid_seq;         out |= next & 0x3F;         return out;     } else {         throw std::runtime_error("invalid utf8 character");     } invalid_seq:     throw std::runtime_error("unexpected end of utf8 sequence"); } 
     

Lista de respuestas

3
 
vote
vote
La mejor respuesta
 

Descripción general

Hay un montón de código repetido que se podría eliminar mediante el uso de funciones.

Cuando Bittwiddling, así, sería bueno para una explicación legible humana de lo que está haciendo. Tuve que buscar la especificación de Unicode para asegurarme de que lo estaba haciendo correctamente.

Un montón de archivos UTF-8 (Stream) contiene un marcador de BOM 0xEF, 0xBB, 0xBF como el primer punto de código. Esto no es parte de la corriente de texto y debe ser descartada si existe. Aunque puede hacer esto en la capa de abstracción por encima de esto, en cuyo caso, se debe agregar un comentario que señala que el marcador de la lista de materiales no se elimina.

No valida que los bytes 2 a 4 tengan el patrón correcto para UTF-8, simplemente haga ese supuesto.

Usos excepciones en los flujos. Normalmente, usted marcará la corriente tan mala y de regreso. Se supone que el usuario de la secuencia revise el estado de la secuencia antes de usar cualquier salida (y la lectura adicional fallará).

C ++ usa operator>> para leer de un flujo. Sería bueno poder leer sus personajes usando este operador.

Revisión del código

El nombre de la función no es correcto:

  chr_t utf32::get_utf32_char(std::istream &in_stream)   

Los puntos de código son distintos de la codificación. Está convirtiendo un punto de código que estaba codificando UTF-8 en UCS-4 (no UTF-32). UTF-32 es otro formato de codificación utilizado para el transporte. Observaría que UCS-4 y UTF-32 parecen iguales, pero no son lo mismo.


Usted lee en next (un INT) En todas las ubicaciones aparte de aquí:

      int next;     chr_t out = in_stream.get();   

¿Por qué no ser consistentes? Me preocupo especialmente por la caja de la esquina y las conversiones automáticas con personajes y enteros. No puedo pensar en nada que salga mal, pero ¿por qué arriesgarlo? LEER EN next (el INT) Verifique que el EOF se convierta en la representación de su personaje.


No uses números mágicos. En este contexto, debe usar EOF (NO -1).

      if (out == -1 || out < 0x80) {         return out;   

Odio else En la misma línea que } .

      } else if ((out & 0xe0) == 0xc0) {   

pero tu código tu estilo.
Muy pocos estándares de codificación utilizan este sistema.

En mi opinión (tan ignorable) no necesita aplastar el código juntos mucho. El espaciado extra vertical hará que el código sea más fácil de leer.


Cuestionario de uso de operator>>0 :

  operator>>1  

¿Por qué no simplemente:

  operator>>2  

Rediseño:

Habría utilizado un enfoque más basado en datos:

  operator>>3  

.

 

Overview

There is a lot of repeated code that could be removed by use of functions.

When bittwiddling like this it would be nice for a human readable explanation of what you are doing. I had to look up the unicode spec to make sure you were doing it correctly.

A lot of UTF-8 files (stream) contain a BOM marker 0xEF, 0xBB, 0xBF as the first code point. This is not part of the text stream and should be discarded if it exists. Though you may do this at the layer of abstraction above this in which case a comment pointing out that the BOM marker is not removed should be added.

You don't validate that the bytes 2 through 4 have the correct pattern for UTF-8 you just make that assumption.

You use exceptions on streams. Normally you would mark the stream as bad and return. The user of the stream is supposed to check the state of the stream before using any output (and further reading will fail).

C++ uses operator>> to read from a stream. It would be nice to be able to read your characters using this operator.

Code Review

The name of the function is not quite correct:

chr_t utf32::get_utf32_char(std::istream &in_stream) 

Code points are distinct from there encoding. You are converting an code point that was encoding UTF-8 into UCS-4 (not UTF-32). UTF-32 is another encoding format used for transportation. I would note that UCS-4 and UTF-32 look the same but they are not the same thing.


You read into next (an int) in all locations apart from here:

    int next;     chr_t out = in_stream.get(); 

Why not be consistent. I especially worry about corner case and auto conversions with characters and integers. Can't think of anything that would go wrong but why risk it. Read into next (the int) check for EOF then convert to your character representation.


Don't use magic numbers. In this context you should use EOF (not -1).

    if (out == -1 || out < 0x80) {         return out; 

I hate else on the same line as }.

    } else if ((out & 0xe0) == 0xc0) { 

But your code your style.
Very few coding standards use this system.

In my opinion (so ignorable) you don't need to crush the code together that much. Extra vertical spacing will make the code easier to read.


Questionablt use of goto:

        if (next == -1) goto invalid_seq; 

Why not simply:

        if (next == EOF) {             throw std::runtime_error(unexpectedESFMessage);         } 

Redesign:

I would have used a more data driven approach:

struct Encoding {     char    mask;     char    value;     int     extra; }; Encoding const utf8Info[] = {                          {0x80, 0x00, 0}                         {0xE0, 0xC0, 1}                         {0xF0, 0xE0, 2}                         {0xF8, 0xF0, 3}                       }; chr_t decodeUtf(std::istream& stream, chr_t result, int count) {     for(; count; --count) {         int next = stream.get();         if (next & 0xC0 != 0x80) {             // Not a valid continuation character             stream.setstate(std::ios::badbit)             return -1;         }         result = (result << 6) | (next & 0x3F);     }     return result; }  chr_t getCodePoint(std::istream& stream) {     // NOTE: Does not remove any initial BOM marker.      int next = stream.get();     if (next == EOF) {         return -1;     }     for(auto const& type: utf8Info) {         if ( next & type.mask == type.value ) {            return decodeUtf(stream, next & ~type.mask, type.extra);         }     }     // Not a valid first character     stream.setstate(std::ios::badbit)     return -1; }  std::istream& operator>>(std::istream& str, chr_t& out) {     chr_t tmp = getCodePoint(str);     if (str) {        out = tmp;     }     return str; } 

.

 
 
   
   

Relacionados problema

4  Macros para detectar UTF-8  ( Macros to detect utf 8 ) 
Estoy trabajando en un programa que maneja los caracteres UTF-8. He hecho las siguientes macros para detectar UTF-8. Los he probado con unos pocos mil palabra...

15  Cuenta byte Longitud de la cadena  ( Count byte length of string ) 
Estoy buscando algunos punteros de orientación y optimización para mi función de JavaScript personalizado que cuenta los bytes en una cadena en lugar de solo ...

5  Convertir una mezcla de Latín 1 y UTF-8 a UTF-8 adecuado  ( Convert a mix of latin 1 and utf 8 to proper utf 8 ) 
El siguiente programa toma una secuencia byte arbitraria como entrada y salidas UTF-8 bien formadas. Todas las secuencias UTF-8 de la entrada se copian sin mo...

4  Code Unicode CodePounts a UTF-8 manualmente  ( Encode unicode codepoints to utf 8 manually ) 
Quiero codificar los puntos de código Unicode a UTF-8 manualmente. Escribí el siguiente código C #. Lo probé con algunos casos que conozco, pero me gustaría s...

7  Convierte la cadena UTF8 a la cadena UTF32 en C  ( Convert utf8 string to utf32 string in c ) 
Estoy haciendo alguna programación recreativa en C (después de pasar algún tiempo en C ++, pero profesionalmente usando solo PHP / JavaScript). Escribí un c...

8  MYUTF-8 PEQUEÑO LIB (validate UTF-8, Guess Language, Count Buds)  ( Myutf 8 small lib validate utf 8 guess language count chars ) 
Soy nuevo en el idioma de C y nunca me conseguí en los detalles de UTF-8, y después de leer Algunos artículos Al respecto, quería intentar jugar con UTF-8 c...

7  Función de lector de caracteres UTF-8  ( Utf 8 character reader function ) 
Puede ver el código completo aquí (nota que el enlace apunta a la confirmación específica). El lenguaje es "limpio C" (es decir, un subconjunto de C89, C9...

5  ¿Mejor código para convertir un carácter a su representación de codificación UTF-8 por ciento?  ( Better code for converting a char to its utf 8 percent encoding representation ) 
Este es un código de trabajo para una implementación de plantilla URI (RFC 6570); Cuando el carácter a renderizar no está dentro de un conjunto de caracteres ...

4  Truncando personaje incompleto UTF-8  ( Truncating incomplete utf 8 character ) 
He creado una función que trunca un carácter UTF-8 incompleto al final de std::string en C ++. La biblioteca estándar de C ++ aún no admite el carácter ba...

8  Comprobación de si un fragmento de cadena podría ser parte de una cadena UTF-8 más larga  ( Checking whether a string fragment could be part of a longer utf 8 string ) 
Aunque la validación UTF-8 es una tarea común, estoy tratando de resolver una tarea ligeramente diferente; Dada una cadena de bytes, haga ejercicio si podría ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos