2011-05-29 8 views
5

estoy trabajando en un escáner léxico codificado a mano rudimentario y deseen apoyar UTF-8 de entrada (que no es más 1970!). los caracteres de entrada se leen de stdin o un archivo de uno en uno y empujaron en un búfer hasta que se vea un espacio en blanco, etc. pensé en escribir mi propia envoltura para fgetc() que en vez volver char[] de bytes que componen el conjunto de caracteres UTF-8 y trabajar con el resultado como una cuerda ... sería bastante fácil, pero se convertiría en una pendiente resbaladiza. Preferiría no perder el tiempo reinventando la rueda y en su lugar usar una biblioteca existente y probada como ICU. Y así que ahora tengo un código de apoyo no UTF-8 que funciona con fgetc(), isspace(), strcmp(), etc., que estoy tratando de actualizar a utilizar en la UCI. Esta es mi primera incursión en la unidad de cuidados intensivos y he estado leyendo la documentación y tratando de encontrar ejemplos de uso con la búsqueda de códigos de Google, pero todavía hay algunos puntos de confusión que espero que alguien pueda aclarar.Preguntas al actualizar un código escáner para utilizar UCI

La función devuelve u_fgetc()UChar y u_fgetcx() vuelve UChar32 ... la documentación recomienda utilizar u_fgetcx() puntos de código para leer, así que eso es lo que estoy empezando. Me quedo con el mismo método que el anterior, pero estoy empujando UChar32 s en un búfer en lugar de char s.

  • ¿Cuál es la forma correcta de comparar un personaje con un valor conocido? Originalmente pude hacer if (c == '+') para verificar si el signo más fue extraído de la entrada. GCC no se queja cuando c es una UChar32 (que es entonces una comparación entre UChar32 y char), pero ¿es realmente adecuado?

  • Pude usar strcmp() para comparar los caracteres almacenados en el búfer con un valor conocido, por ejemplo if ((strcmp(buf, "else") == 0). Hay u_strcmp() proporcionada por la UCI y yo creo que puede que tenga que utilizar los U_STRING_DECL y U_STRING_INIT macros para especificar el conocido literal, pero no estoy seguro. La documentación muestra que resultan en UChar[], aunque supongo que necesito UChar32[] ... y estoy seguro de cómo usarlos correctamente todos modos. Cualquier orientación aquí sería bienvenida.

  • Después de leer una serie de caracteres numéricos, los he convertido con strtol() para poder trabajar con ellos. ¿Hay una función similar disponible por ICU desde que estoy convirtiendo UChar32[] ahora?

Respuesta

5

UChar es para la celebración de una Unidad Código , mientras UChar32 es para la celebración de un código de punto. Si la entrada se mantiene en la Basic Multilingual Plane (BMP), UChar es suficiente, y de hecho la mayoría de las funciones de la UCI operan sobre UChar[].

lectura más recomendada es la ICU User Guide, lo que explica la mayor parte de los componentes internos y las mejores prácticas.

  • ¿Cuál es la forma correcta de comparar una variable de caracteres Unicode en contra de un valor conocido? un carácter (o UChar o UChar32) es otro tipo entero con una cierta anchura y de signo, y puede ser comparado a otros tipos de enteros con las salvedades y restricciones habituales.En cuanto a la definición de un valor de carácter, C99 (capítulo 6.4.3) proporciona nombres carácter universal Notación: \u seguido de cuatro dígitos hexadecimales, o \U seguido de ocho dígitos hexadecimales, especificando la ISO/IEC 10646 "identificador corto". El área debajo de 0x00a0 (con excepciones de 0x0024 '$', 0x0040 '@' y 0x0060 (backtick) está reservada (pero se puede representar al convertir una constante de carácter simple en UChar). También se reserva el rango de 0xd800 a 0xdfff (para uso de UTF -16).

  • cómo definir literales de cadena Unicode?U_STRING_DECL y U_STRING_INIT son en realidad lo que estás buscando. (Como se ha dicho anteriormente, UCI opera principalmente en UChar[].) Si estaba utilizando C++ en lugar de C , UNICODE_STRING_SIMPLE (seguido opcionalmente por getTerminatedBuffer() para obtener UChar[] nuevamente) proporciona una forma mucho más cómoda de definir literales de cadenas Unicode.

  • Cómo convertir una cadena Unicode que representa un número en el valor numérico?unum_parse() y sus hermanos en unum.h te ayudarán allí.

+0

Excelentes respuestas, solo enfatizaré para otros lectores: hacer sus comparaciones en Unicode, no como char * s. (Entonces no use "x" o "x"). De lo contrario, podría encontrarse con problemas de codepage. –

2
  1. el valor Unicode para SIGN PLUS es U + 002B, y el (Latin-1) valor normal para '+' es también 0x2B (053, 43). Lo que escribió es lo suficientemente seguro donde el conjunto de códigos se basa en ASCII o ISO-8859-x. El estándar C99 proporciona Unicode (nombres de caracteres universales) de los formularios \u0123 y \U00102345 (con 4 y 8 dígitos hexadecimales), pero estipula que no puede especificar valores inferiores a \u00A0, como \u002B. Entonces, creo que lo que escribiste es correcto.

    Sin embargo, usted podría ahorrarse la angustia futuro mediante el uso de un enum como

    enum { PLUS_SIGN = '+' }; 
    

    definió en un encabezado apropiado y utilizado dondequiera que necesita un literal signo más. De esa manera, si su suposición (y mi suposición) es incorrecta, tiene un lugar para editar: el encabezado.

    Noto que la página en Strings con ICU sugiere que usar UTF-32 en una aplicación es inusual.

  2. En C puro, lo que probablemente utilice wcscmp(buf, L"else"), en el supuesto de que el wchar_t en su sistema es equivalente a uint32_t y/o UChar32. Parece que hay formas de usar UnicodeString y UNICODE_STRING("...") seguidas por ToUTF32() para crear una cadena UTF-32. También puede haber formas más ordenadas.

  3. Hay clases de 'Formato' que manejan tanto el formateo como el análisis sintáctico. Probablemente usaría clases derivadas de la clase NumberFormat.

Cuestiones relacionadas