Sign in Join
Wiki copytemporary

FPC Unicode support/es

English · Español · Français · Русский

Introducción

Hasta FPC 2.6.x, incluido FPC 2.6.x, el RTL se basaba en los de Turbo Pascal y Delphi 7. Esto significa que se basaba principalmente en los tipos shortstring, ansistring y pchar. Ninguno de estos tipos tenía ninguna información de codificación asociada a ellos, pero se supone implícitamente que está codificado en la "codificación predeterminada del sistema" y se transmitió a las llamadas a la API del S.O. sin ninguna conversión.

En Delphi 2009, Embarcadero cambió toda la RTL al tipo UnicodeString, que representa cadenas mediante UTF-16. Además, también hicieron que el tipo AnsiString "code page-aware" (reconocimiento de página de códigos). Esto significa que AnsiStrings a partir de entonces contienen la página de códigos según la cual se deben interpretar sus datos.

La compatibilidad de nivel de lenguaje de FPC para estos tipos de cadena ya está disponible en las versiones estables actuales del compilador (FPC 3.0.0 y versiones superiores). El soporte de nivel RTL aún no está completo. Esta página ofrece una visión general del comportamiento relacionado con la página de códigos de estos tipos de cadena, el nivel actual de compatibilidad en el RTL y las posibles formas futuras de cómo se puede mejorar esta compatibilidad.

Retrocompatibilidad

Si tiene código existente que funciona de forma definida () con una versión anterior de FPC y no realiza ningún cambio en él, debe seguir funcionando sin modificar con la nueva versión de FPC. Garantizar esto es el propósito principal de la multitud de variables defaultCodePage y sus valores predeterminados como se describe a continuación.

(*) esto significa principalmente: no se almacenan datos en una ansistring que se ha codificado con algo más que la página de códigos predeterminada del sistema y, posteriormente, se pasa esta cadena tal cual a una rutina FPC RTL. Por ejemplo, el código Lazarus actual es generalmente fino, ya que se supone que debe llamar a UTF8ToAnsi() antes de pasar sus cadenas a las rutinas FPC RTL.

Si su código existente usó ansistrings de una manera no soportada, es decir, almacenando datos en él que no están codificados en la página de código predeterminado del sistema y no teniendo cuidado al interactuar con otro código (como las rutinas RTL), todavía puede ser capaz de trabajar en la mayoría de los problemas si estos datos siempre utilizan la misma codificación. En ese caso, puede llamar a SetMultiByteConversionCodePage() al iniciar su programa, y como argumento, la página de códigos de los datos que contienen las ansistrings. Tenga en cuenta que esto también afectará a la interpretación de todos los datos ShortString, AnsiChar y PAnsiChar.

Código de páginas

Un código de páginas define cómo se deben interpretar los bytes individuales de una cadena (string), es decir, qué letra, símbolo u otro carácter gráfico corresponde a cada byte o secuencia de bytes.

Identificadores de códigos de página

Un identificador de código de página siempre se almacena como un TSystemCodePage, que es un alias para Word. El valor representa el código correspondiente según lo definido por [http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx Microsoft Windows]. Además, hay 3 valores de códigos de página especiales:

Nota: los identificadores de códigos de página son diferentes de los nombres de códigos de página que se utilizan en las directivas {$codepage xxx} (que ya está disponible en la versión estable de FPC actual). Los nombres de códigos de páginas son los nombres de unidades de códigos de página individuales expuestos por la unidad charset, que tienen nombres como cp866, cp1251 y utf8.

Configuración del código de página

La unidad del sistema contiene varias variables globales que indican el código de página predeterminado utilizado para determinadas operaciones.

DefaultSystemCodePage

DefaultFileSystemCodePage

DefaultRTLFileSystemCodePage

Código de página del archivo fuente

El código de página del archivo fuente determina cómo se interpretan las constantes de cadena, y donde el compilador insertará operaciones de conversión del código de página al asignar un tipo de cadena a otro.

Los códigos de página del archivo fuente se determinan de la siguiente manera:

Strings

String/character types

Shortstring

El código de página de un shortstring es implícitamente CP_ACP y por lo tanto siempre será igual al valor actual de Defaultsysticacodepage.

PAnsiChar/AnsiChar

Estos tipos son los mismos que los tipos PChar/Char antiguos. En todos los modos del compilador, excepto en el {$mode delphiunicode}, PChar/Char también son alias para PAnsiChar/AnsiChar. Su código de páginas es implícitamente CP_ACP y, por lo tanto, siempre será igual al valor actual de DefaultSystemCodePage.

PWideChar/PUnicodeChar y WideChar/UnicodeChar

Estos tipos permanecen sin cambios. WideChar/UnicodeChar puede contener una sola unidad de código UTF-16, mientras que PWideChar/PUnicodeChar apunta a una sola matriz o a una matriz de unidades de código UTF-16.

En {$mode delphiunicode}, PChar se convierte en un alias para PWideChar/PUnicodeChar y Char se convierte en un alias para WideChar/UnicodeChar.

UnicodeString/WideString

Estos tipos se comportan igual que en versiones anteriores:

Ansistring

AnsiStrings son tipos de conteo de referencia con una longitud máxima de bytes High(SizeInt). Además, ahora también tienen información del código de página asociado con ellos.

Lo más importante que debe comprender sobre el nuevo tipo AnsiString es que tiene una página de códigos declarada/estática/preferida/predeterminada (denominada página de códigos declarada a partir de ahora) y una página de códigos dinámica. La página de códigos declarada indica al compilador que al asignar algo a ese AnsiString, primero debe convertir los datos a esa página de códigos declarada (excepto si es CP_NONE, vea RawByteString a continuación). La página de códigos dinámicos es una propiedad de la AnsiString que, similar a la longitud y el recuento de referencias, define la página de códigos real de los datos que actualmente tiene ese AnsiString.

Códigos de página declarados

El código de páginas declarado de un AnsiString sólo se puede definir declarando un nuevo tipo (type) de la siguiente manera:

pascal
type
  CP866String = type AnsiString(866);

El código de página declarado de una variable declarada como AnsiString sin formato es CP_ACP. En efecto, el tipo AnsiString ahora se define semánticamente en la unidad System como:

pascal
type
  AnsiString = type AnsiString(CP_ACP);

Otro tipo AnsiString(X) predefinido en la unidad System es UTF8String:

pascal
type
  UTF8String = type AnsiString(CP_UTF8);

Una vez que haya definido un tipo AnsiString(X) personalizado, puede usarlo para declarar variables, parámetros, campos, etc. como de costumbre.

Tenga en cuenta que CP_UTF16 y CP_UTF16BE no son válidos como páginas de códigos para AnsiStrings. El resultado de definir un AnsiString con una página de códigos es indefinido.

Código de páginas dinámico

Si un string con un código de página declarado SOURCE_CP se asigna a un string con el código de página declarado DEST_CP, entonces: If a string with a declared code page SOURCE_CP is assigned to a string with declared code page DEST_CP , then

Estas reglas significan que es perfectamente posible para una variable AnsiString obtener una página de códigos dinámica que difiere de su página de códigos declarada. Por ejemplo, en el tercer caso SOURCE_CP podría ser CP_ACP, mientras que después de la asignación puede tener una página de códigos dinámica igual a DefaultSystemCodePage.

Nota: como se mencionó anteriormente, si se produce o no una posible conversión de página de códigos depende únicamente de las páginas de códigos declaradas de las cadenas implicadas. Esto significa que si asigna un AnsiString(X) a otro AnsiString(X) y el código dinámico del primero era diferente de X, los datos de cadena no se convertirán en la página de códigos X por la asignación.

RawByteString

El tipo (type) RawByteString se define como:

pascal
type
  RawByteString = type AnsiString(CP_NONE);

Como se mencionó anteriormente, los resultados de las operaciones en cadenas con la página de códigos CP_NONE son indefinidos. Como no tiene sentido definir un tipo en el RTL cuyo comportamiento es indefinido, el comportamiento de RawByteString es algo diferente al de otros tipos AnsiString(X).

Como una primera aproximación, RawByteString se puede considerar como un "AnsiString sin tipo": asignar un AnsiString(X) a un RawByteString tiene exactamente el mismo comportamiento que asignar ese AnsiString(X) a otra variable AnsiString(X) con el mismo valor de X: ningún código la conversión o copia de páginas se produce, solo se aumenta el recuento de referencias.

Menos intuitivo es probablemente que cuando un RawByteString se asigna a un AnsiString(X), lo mismo sucede: no hay conversión de página de códigos o copia, sólo se aumenta el recuento de referencias. Tenga en cuenta que esto significa que los resultados de las funciones que devuelven un RawByteString nunca se convertirán a la página de códigos declarada del destino. Esta es otra forma en la que la página de códigos dinámicos de un AnsiString(X) puede ser diferente de su página de códigos declarada.

Este tipo se utiliza principalmente para declarar const, constref y parámetros de valor que aceptan cualquier valor AnsiString(X) sin convertirlo en una página de códigos declarada predefinida. Tenga en cuenta que si lo hace, la rutina que acepta esos parámetros debe ser capaz de controlar cadenas con cualquier página de códigos dinámico posible.

Los parámetros var y out también se pueden declarar como RawByteString, pero en este caso el compilador dará un error si un AnsiString(X) cuya página de códigos declarada es diferente de CP_NONE se pasa. Esto es coherente con los parámetros var y out en general: requieren que se pase un tipo exactamente coincidente. Puede agregar una conversión de tipo RawByteString() explícita alrededor de un argumento para eliminar este error, pero debe estar preparado para tratar el hecho de que la cadena devuelta puede tener cualquier página de códigos dinámicos.

Concatenaciones de cadenas (strings)

Normalmente, en Pascal el tipo de resultado de una expresión es independiente de cómo se utiliza su resultado después. Por ejemplo, multiplicar dos longints en una plataforma de 32 bits y asignar el resultado a un int64 seguirá realizando la multiplicación usando la aritmética de 32 bits, y sólo después el resultado se convierte a 64 bits.

Las cadenas compatibles con la página de códigos son la única excepción a esta regla: la concatenación de dos o más cadenas siempre se produce sin pérdida de datos, aunque después la cadena resultante, por supuesto, se seguirá convirtiendo en la página de códigos declarada del destino (lo que puede resultar pérdida de datos).

Asignar el resultado de una concatenación a un RawByteString es de nuevo especial:

String constants

El compilador tiene que conocer la página de códigos según la cual debe interpretar las constantes de cadena (string constants), ya que puede tener que convertirlas en tiempo de compilación. Normalmente, una constante de cadena se interpreta según la página de códigos del archivo fuente. Si la página de códigos del archivo fuente es CP_ACP, se utiliza un valor predeterminado en su lugar: en ese caso, durante las conversiones se supone que las cadenas constantes tienen la página de códigos 28591 (ISO 8859-1 Latin 1; Europa Occidental).

Cuando se asigna una constante de cadena a un AnsiString(X) en el código o como parte de una constante con tipo o una inicialización variable, entonces:

De forma similar, si se asigna una constante de cadena a un UnicodeString, la constante de cadena se convierte, en tiempo de compilación, de la página de códigos del archivo fuente a UTF-16.

Para ShortString y PChar, se sigue la misma regla que para AnsiString(CP_ACP).

Tenga en cuenta que las constantes de cadena simbólicas se convertirán en tiempo de compilación en el tipo de cadena y la página de códigos adecuados siempre que se usen. Esto significa que no hay ninguna sobrecarga de velocidad cuando se usa una sola constante de cadena en varios contextos de tipo de cadena y página de códigos, solo alguna sobrecarga de tamaño de datos.

De lo anterior se deduce que para garantizar una interpretación predecible de las constantes de cadena en el código fuente, es mejor incluir una directiva explícita de {$codepage xxx} (o usar la opción de línea de comandos equivalente -Fc), o guardar el código fuente en UTF-8 con un BOM.

Indexado de cadenas (strings)

Nada cambia en la indexación de cadenas. Cada elemento de cadena de un UnicodeString/WideString es de dos bytes y cada elemento de cadena de todas las demás cadenas es de un byte. El mecanismo de indexación de cadenas omite completamente los códigos de páginas y los puntos de código compuestos.

Cambios en la RTL

Para garantizar completamente la integridad de los datos en presencia de cadenas compatibles con la página de códigos, se deben adaptar todas las rutinas de la RTL y los paquetes que aceptan parámetros AnsiString. La razón es que si sus parámetros siguen siendo simples AnsiString, cualquier cadena con una página de códigos declarada diferente se convertirá en DefaultSystemCodePage cuando se pasa. Esto puede provocar la pérdida de datos. Hasta ahora, las rutinas que se ocupan principalmente del acceso al sistema de archivos se han actualizado para conservar todos los datos de caracteres. A continuación se muestra una lista exhaustiva de todas las rutinas que conservan la codificación de cadenas en FPC 3.0. A menos que se indique explícitamente lo contrario, todas estas rutinas también tienen sobrecargas que aceptan parámetros unicodeString.

RTL ToDo

Como la lista anterior es exhaustiva, no existen otras rutinas RTL que soporten páginas de código arbitrarias. Esta sección contiene una lista de los errores que algunas personas han identificado y, si es posible, soluciones. Tenga en cuenta que las rutinas no mencionadas aquí ni arriba son igualmente inseguras como las que se mencionan explícitamente.

TFormatSettings y DefaultFormatSettings

El tipo de ThousandSeparator y DecimalSeparator es del tipo AnsiChar. Esto significa que si DefaultSystemCodePage es UTF-8 y el separador de la configuración regional tiene más de un byte de largo en esa codificación, estos campos no son lo suficientemente grandes. Algunos ejemplos son el carácter de espacio en blanco "non-breaking" del francés y ruso que se utiliza para representar el ThousandSeparator.

Secciones antiguas u obsoletas

Warning: Estas secciones se mantienen para referencia histórica - por favor actualice las secciones anteriores con esta información si todavía es aplicable. Desde FPC 2.7 (versión de desarrollo antes del lanzamiento de 3.0.0), se ha implementado un amplio soporte Unicode.

Cambios visibles para el usuario

La compatibilidad completa con cadenas compatibles con la página de códigos no es posible sin romper algún código existente. La siguiente lista intenta resumir los cambios visibles al usuario más importantes.

Ver también


From the Free Pascal wiki, page "FPC Unicode support/es", as it stood on 2020-02-16 after a change by GAN, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.