Unicode dans RAD Studio
Remonter à Introduction à RAD Studio
RAD Studio utilise les chaînes ANSI, c'est-à-dire, le type string
est désormais une chaîne Unicode (System.UnicodeString), non plus une chaîne ANSI. Cette rubrique décrit ce que vous devez savoir pour gérer correctement les chaînes.
Si vous voulez utiliser des chaînes ANSI ou des chaînes étendues, utilisez les types AnsiString and WideString.
RAD Studio est entièrement compatible Unicode, et des modifications pourraient être requises sur les parties de votre code qui impliquent la gestion de chaînes. Toutefois, tous les efforts ont été effectués pour minimiser ces modifications. Bien que de nouveaux types de données ont été introduits, les types de données existants ont été conservés et ils fonctionnent comme auparavant. Grâce à l'expérience maison de la conversion Unicode, les applications de développeurs existantes devraient migrer assez bien.
Pour des ressources supplémentaires :
- Delphi Unicode Migration for Mere Mortals: Stories and Advice from the Front Lines, par Cary Jensen (EN)
- Ressources de migration Unicode pour Delphi, C++Builder et RAD Studio
Sommaire
- 1 Types de chaînes existants
- 2 Nouveau type de chaîne : UnicodeString
- 3 Conditions du compilateur
- 4 Résumé des modifications
- 5 Résumé de ce qui n'a pas changé
- 6 Constructions de code indépendantes de la taille des caractères
- 7 Constructions de code dépendantes de la taille des caractères
- 8 Constructions Set of Char
- 9 Méfiez-vous de ces constructions
- 10 Bibliothèque d'exécution
- 11 Composants et classes
- 12 BOM (Byte Order Mark)
- 13 Etapes d'activation pour Unicode de vos applications
- 14 Nouveaux avertissements du compilateur Delphi
- 15 Recommandations
- 16 Voir aussi
Types de chaînes existants
Les types de données pré-existants AnsiString
et System.WideString
fonctionnent comme auparavant.
Les chaînes courtes fonctionnent aussi comme auparavant. Notez que les chaînes courtes sont limitées à 255 caractères et contiennent seulement un nombre de caractères et des données caractère à octet unique. Elles ne contiennent pas des informations de page de code. Une chaîne courte peut contenir des données UTF-8 pour une application particulière, mais ce n'est généralement pas le cas.
AnsiString
Auparavant, string était un alias pour AnsiString. Ce tableau présente l'emplacement des champs au format précédent de AnsiString
:
Format précédent du type de données AnsiString
:
Comptage de références | Longueur | Données chaîne (en octets) | Terme Null |
---|---|---|---|
-8 |
-4 |
0 |
Length |
Pour RAD Studio, le format de AnsiString a changé. Deux nouveaux champs (CodePage
et ElemSize
) ont été ajoutés. Cela rend le format deAnsiString identique pour le nouveau type UnicodeString. (Pour davantage d'informations sur ce nouveau format, voir Types chaîne longue.)
WideString
System.WideString
était auparavant utilisé pour les données caractères Unicode. Son format est essentiellement le même que le BSTR
Windows. WideString
est toujours approprié dans les applications COM.
Nouveau type de chaîne : UnicodeString
Le type string
de RAD Studio est le type UnicodeString
.
Pour Delphi, les types Char
et PChar
sont maintenant respectivement WideChar
et PWideChar
.
string
était un alias pour AnsiString
, et les types Char
et PChar
étaient respectivement AnsiChar
et PAnsiChar
.Pour C++, l'option Mappage de _TCHAR en contrôle la définition flottante de _TCHAR
, qui peut être wchar_t
ou char
.
Les frameworks et bibliothèques de RAD Studio utilisent désormais le type UnicodeString
; ils ne représentent plus les valeurs de chaînes sous forme de chaînes sur un seul octet ou MBCS.
Format du type de données UnicodeString
:
Page de code | Taille d'élément | Comptage de références | Longueur | Données chaîne (en éléments) | Terme Null |
---|---|---|---|---|---|
-12 |
-10 |
-8 |
-4 |
0 |
Length * elementsize |
UnicodeString
peut être représenté comme la structure Delphi suivante :
type StrRec = record CodePage: Word; ElemSize: Word; refCount: Integer; Len: Integer; case Integer of 1: array[0..0] of AnsiChar; 2: array[0..0] of WideChar; end;
UnicodeString
ajoute la page de code CodePage
et les champs de taille d'élément ElemSize
qui décrivent le contenu de la chaîne. UnicodeString
est compatible en assignation à tous les autres types chaîne. Toutefois, les assignations entre AnsiString
et UnicodeString
effectuent toujours les conversions appropriées vers le bas et vers le haut. Notez que l'assignation d'un type UnicodeString
à un type AnsiString
n'est pas recommandée et peut générer une perte de données.
Notez que AnsiString
a aussi les champs CodePage
et ElemSize
.
Les données UnicodeString
sont au format UTF-16 pour les raisons suivantes :
- UTF-16 correspond au format du système d'exploitation sous-jacent.
- UTF-16 réduit les conversions explicites/implicites supplémentaires.
- Il offre de meilleures performances lors de l'appel de l'API Windows.
- Avec UTF-16, le système d'exploitation n'a pas besoin d'effectuer des conversions.
- Le BMP (Basic Multilingual Plane) contient déjà la vaste majorité des glyphes de langage actifs dans le monde et tient dans un
Char
UTF-16 (16 bits) unique. - Les paires de substitution Unicode sont analogues au jeu de caractères multi-octets (MBCS), mais plus prévisibles et standard.
UnicodeString
peut fournir des conversions implicites sans perte, vers et depuisWideString
pour les interfaces COM de marshaling.
Les caractères en UTF-16 peuvent occuper 2 ou 4 octets. Ainsi, le nombre des éléments d'une chaîne n'est pas nécessairement égal au nombre de caractères. Si la chaîne ne comporte que des caractères BMP, le nombre de caractères et le nombre d'éléments sont égaux.
UnicodeString
offre les avantages suivants :
- Il utilise le comptage de références.
- Il résout un ancien problème d'application dans C++Builder.
- L'emploi de
AnsiString
pour transporter les informations d'encodage (page de code) réduit le problème de perte de données potentiel avec les transtypages implicites. - Le compilateur garantit que les données sont correctes avant la mutation des données.
WideString
n'utilise pas le comptage de références, et UnicodeString
est ainsi plus flexible et efficace dans la plupart des types d'applications (WideString
est plus approprié à COM).
Indexation
Les instances de UnicodeString
peuvent indexer les caractères. L'indexation est à base 1, comme pour AnsiString
. Considérons le code suivant :
var C: Char; S: string; begin ... C := S[1]; ... end;
Dans un cas comme celui présenté ci-dessus, le compilateur doit s'assurer que les données de S
sont au format approprié. Le compilateur génère du code pour s'assurer que les assignations aux éléments chaîne ont le type approprié et que l'instance est unique (c'est-à-dire que le nombre de références est égal à 1) via un appel à une fonction UniqueString
. Pour le code ci-dessus, puisque la chaîne peut contenir des données Unicode, le compilateur doit aussi appeler la fonction UniqueString
appropriée avant l'indexation dans le tableau de caractères.
Conditions du compilateur
Dans Delphi et C++Builder, vous pouvez utiliser des conditions pour autoriser le code Unicode et le code non-Unicode dans le même source.
Delphi
{$IFDEF UNICODE}
C++Builder
#ifdef _DELPHI_STRING_UNICODE
Résumé des modifications
string
est maintenant mappé enUnicodeString
, pas enAnsiString
.Char
est maintenant mappé enWideChar
(2 octets, pas 1 octet) et est un caractère UTF-16.PChar
est maintenant mappé enPWideChar
.- Dans C++,
System::String
est maintenant mappé en classeUnicodeString
.
Résumé de ce qui n'a pas changé
AnsiString
.WideString
.AnsiChar
,PAnsiChar
.WideChar
,PWideChar
- Les conversions implicites fonctionnent toujours.
AnsiString
utilise la page de code active de l'utilisateur.
Constructions de code indépendantes de la taille des caractères
Les opérations suivantes ne dépendent pas de la taille des caractères :
- Concaténation de chaînes
<var chaîne> + <var chaîne>
<var chaîne> + <littéral>
<littéral> + <littéral>
Concat(<chaîne> , <chaîne>)
- Fonctions chaîne standard
Length(<chaîne>)
renvoie le nombre d'éléments char, qui peut être différent du nombre d'octets. Notez que la fonctionSizeOf
renvoie le nombre d'octets, ce qui signifie que la valeur de retour deSizeOf
peut différer de celle deLength
.Copy(<chaîne>, <début>, <longueur>)
renvoie une sous-chaîne d'élémentsChar
.Pos(<sous-chaîne>, <chaîne>)
renvoie l'index du premier élémentChar
.
- Opérateurs
<chaîne> <opérateur_comparaison> <chaîne>
CompareStr()
CompareText()
...
FillChar(<structure ou mémoire>)
FillChar(Rect, SizeOf(Rect), #0)
FillChar(WndClassEx, SizeOf(TWndClassEx), #0)
. Notez queWndClassEx.cbSize := SizeOf(TWndClassEx);
- API Windows
- Les appels API sont initialisés par défaut à leurs versions
WideString
("W"). - Le transtypage
PChar(<chaîne>)
a une sémantique identique.
- Les appels API sont initialisés par défaut à leurs versions
Exemple GetModuleFileName
:
function ModuleFileName(Handle: HMODULE): string; var Buffer: array[0..MAX_PATH] of Char; begin SetString(Result, Buffer, GetModuleFileName(Handle, Buffer, Length(Buffer))); end;
Exemple GetWindowText
:
function WindowCaption(Handle: HWND): string; begin SetLength(Result, 1024); SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result))); end;
Exemple d'indexation de caractères chaîne :
function StripHotKeys(const S: string): string; var I, J: Integer; LastChar: Char; begin SetLength(Result, Length(S)); J := 0; LastChar := #0; for I := 1 to Length(S) do begin if (S[I] <> '&') or (LastChar = '&') then begin Inc(J); Result[J] := S[I]; end; LastChar := S[I]; end; SetLength(Result, J); end;
Constructions de code dépendantes de la taille des caractères
Certaines opérations dépendent de la taille des caractères. Les fonctions et les fonctionnalités de la liste suivante incluent aussi une version "portable" quand c'est possible. Vous pouvez de façon similaire réécrire votre code afin qu'il soit portable, c'est-à-dire qu'il fonctionne à la fois avec les variables AnsiString
et UnicodeString
.
SizeOf(<tableau car>)
- utilisez la fonction portableLength(<tableau car>)
.Move(<tampon car>... CharCount)
- utilisez la fonction portableMove(<tampon car> ... CharCount * SizeOf(Char))
.- Stream Read/Write - utilisez la fonction portable
AnsiString
,SizeOf(Char)
ou la classeTEncoding
. FillChar(<tableau car>, <taille>, <AnsiChar>)
- utilisez la fonction*SizeOf(Char)
si remplissage par#0
, ou la fonction portableStringOfChar
.GetProcAddress(<module>, <PAnsiChar>)
- utilisez la fonction de surcharge fournie prenant unPWideChar
.- Transtypage ou utilisation de
PChar
pour l'arithmétique de pointeur - Placez{IFDEF PByte = PChar}
au début du fichier si vous utilisezPChar
pour l'arithmétique de pointeur. Ou bien utilisez la directive du compilateur Delphi{POINTERMATH <ON|OFF>}
pour activer l'arithmétique de pointeur pour tous les pointeurs typés, afin que l'incrémentation / décrémentation se fasse par taille d'élément.
Constructions Set of Char
Vous pouvez modifier ces constructions.
- <Char> in <set of
AnsiChar
> - la génération du code est correcte (les caractères>#255
ne sont jamais dans l'ensemble). Le compilateur affiche l'avertissementWideChar réduit dans les opérations d'ensemble
. Selon votre code, vous pouvez désactiver en toute sécurité l'avertissement. Vous pouvez aussi utiliser la fonctionCharinSet
. - <Char> in
LeadBytes
- l'ensembleLeadBytes
global est pour les locales MBCS ANSI. UTF-16 a toujours la notion d'un "lead char" (#$D800 - #$DBFF
: substituts étendus,#$DC00 - #$DFFF
: substituts faibles). Pour changer cela, utilisez la fonction surchargéeIsLeadChar
. La version ANSI est confrontée àLeadBytes
. La versionWideChar
vérifie si c'est un substitut faible / étendu. - Classification des caractères - utilisez la classe statique
TCharacter
. L'unitéCharacter
offre des fonctions pour classifier les caractères :IsDigit
,IsLetter
,IsLetterOrDigit
,IsSymbol
,IsWhiteSpace
,IsSurrogatePair
, et ainsi de suite. Elles sont basées sur les données de table directement de Unicode.org.
Méfiez-vous de ces constructions
Vous devriez examiner les constructions de code problématiques suivantes :
- Transtypages qui masquent le type
AnsiString(Pointer(foo))
- Revoir pour correction : qu'était-il prévu ?
- Transtypages suspects - génèrent un avertissement
PChar(<AnsiString var>)
PAnsiChar(<UnicodeString var>)
- Construction, manipulation ou accès direct aux structures internes de chaînes. Certaines fonctions, comme
AnsiString
, ont été modifiées en interne, ce n'est donc pas sécurisé. UtilisezStringRefCount
,StringCodePage
,StringElementSize
et d'autres fonctions pour obtenir des informations de chaîne.
Bibliothèque d'exécution
- Surcharges. Pour les fonctions qui prennent
PChar
, il existe maintenant les versionsPAnsiChar
etPWideChar
afin que la fonction appropriée soit appelée. - Les fonctions
AnsiXXX
sont prises en considération- Fonctions
SysUtils.AnsiXXXX
, telles queAnsiCompareStr
- Reste déclaré avec
string
et migre versUnicodeString
. - Offre une meilleure compatibilité descendante (pas besoin de changer le code).
- Reste déclaré avec
- Les fonctions
AnsiXXXX
de l'unitéAnsiStrings
offrent les mêmes capacités que les fonctionsSysUtils.AnsiXXXX
, mais elles fonctionnent seulement pourAnsiString
. En outre, les fonctionsAnsiStrings.AnsiXXXX
fournissent de meilleures performances pour unAnsiString
que les fonctionsSysUtils.AnsiXXXX
, qui fonctionnent pourAnsiString
etUnicodeString
, car aucune conversion implicite n'est effectuée.
- Fonctions
Write/Writeln
etRead/Readln
PByte
- déclarée avec$POINTERMATH ON
. Cela permet l'indexation de tableau et la fonction mathématique de pointeur commePAnsiChar
.
- Fonctions d'informations de chaînes
StringElementSize
renvoie la taille réelle des données.StringCodePage
renvoie la page de code des données chaîne.System.StringRefCount
renvoie le comptage de références.
- La RTL fournit des fonctions d'assistance qui permettent aux utilisateurs de faire des conversions explicites entre les pages de codes et les conversions de taille d'éléments. Si les développeurs utilisent la fonction
Move
sur un tableau de caractères, ils ne peuvent pas faire de supposition sur la taille des éléments. Ce problème peut être atténué en s'assurant que toutes les références RValue génèrent les appels appropriés à RTL pour garantir des tailles d'éléments correctes.
Composants et classes
TStrings
: StockeUnicodeString
en interne (reste déclaré commestring
).TWideStrings
(dépréciable) est inchangé. UtiliseWideString
(BSTR) en interne.TStringStream
- A été réécrite - initialisée à l'encodage ANSI par défaut pour le stockage interne.
- L'encodage peut être redéfini.
- Considérez l'utilisation de
TStringBuilder
au lieu deTStringStream
pour construire une chaîne à partir de morceaux.
TEncoding
- Initialisée par défaut à la page de code active de l'utilisateur.
- Prend en charge UTF-8.
- Prend en charge UTF-16, Big Endian et Little Endian.
- Prise en charge de de BOM (Byte Order Mark).
- Vous pouvez créer des classes descendantes pour les encodages spécifiques aux utilisateurs.
- Flux de composants (fichiers DFM texte)
- Compatibilité descendante complète.
- Flux en UTF-8 seulement si le type de composant, la propriété ou le nom contient des caractères non-ASCII-7.
- Les valeurs des propriétés de chaînes sont toujours mises en flux au format d'échappement "#".
- Peut aussi autoriser les valeurs en UTF-8.
- Seule la modification au format binaire est potentielle pour les données UTF-8 pour le nom de composant, les propriétés et le nom de type.
BOM (Byte Order Mark)
Le BOM (Byte Order Mark) doit être ajouté aux fichiers pour indiquer leur encodage :
- UTF-8 utilise
EF BB BF
. - UTF-16 Little Endian utilise
FF FE
. - UTF-16 Big Endian utilise
FE FF
.
Etapes d'activation pour Unicode de vos applications
Vous devez effectuer ces étapes :
- Revoir les fonctions relatives aux chaînes et aux caractères.
- Reconstruire l'application.
- Revoir les paires de substitution.
- Revoir les charges utiles des chaînes.
Pour de plus amples détails, voir Activation de vos applications pour Unicode.
Nouveaux avertissements du compilateur Delphi
De nouveaux avertissements ont été ajoutés au compilateur Delphi concernant des erreurs possibles de transtypage (par exemple, depuis un UnicodeString
ou un WideString
vers un AnsiString
ou AnsiChar
). Quand vous convertissez une application en Unicode, vous devez activer les avertissements 1057 et 1058 pour obtenir de l'assistance dans la recherche des zones de problèmes de votre code.
- W1050 WideChar réduit en byte char dans les expressions ensemble (Delphi). "Set of char" de Win32 définit un ensemble sur l'étendue entière du type Char. Puisque Char est un type dimensionné en octets dans Win32, cela définit un ensemble de taille maximale contenant 256 éléments. Dans .NET, Char est un type dimensionné en mot, et cette étendue (0..65535) dépasse la capacité du type ensemble.
- W1057: Transtypage de chaîne implicite de '%s' en '%s' (IMPLICIT_STRING_CAST) Emis quand le compilateur détecte un cas où il doit convertir implicitement un
AnsiString
(ouAnsiChar
) en un format Unicode (unUnicodeString
ou unWideString
). (REMARQUE : Cet avertissement sera éventuellement activé par défaut). - W1058: Transtypage de chaîne implicite avec perte de données potentielle de '%s' en '%s' (IMPLICIT_STRING_CAST_LOSS) Emis quand le compilateur détecte un cas où il doit convertir implicitement un format Unicode (un
UnicodeString
ou unWideString
) en unAnsiString
(ouAnsiChar
). C'est une conversion à perte potentielle puisqu'il est possible que certains caractères de la chaîne ne puissent pas être représentés dans la page de code dans laquelle la chaîne est convertie. (REMARQUE : Cet avertissement sera éventuellement activé par défaut). - W1059: Transtypage de chaîne explicite de '%s' en '%s' (EXPLICIT_STRING_CAST) Emis quand le compilateur détecte un cas où le programmeur transtype explicitement un
AnsiString
(ouAnsiChar
) en un format Unicode (UnicodeString
ouWideString
). (REMARQUE : Cet avertissement sera toujours désactivé par défaut et ne doit être utilisé que pour localiser des problèmes potentiels). - W1060: Transtypage de chaîne explicite avec perte de données potentielle de '%s' en '%s' (EXPLICIT_STRING_CAST_LOSS) Emis quand le compilateur détecte un cas où le programmeur transtype explicitement un format Unicode (
UnicodeString
ouWideString
) enAnsiString
(ouAnsiChar
). C'est une conversion à perte potentielle puisqu'il est possible que certains caractères de la chaîne ne puissent pas être représentés dans la page de code dans laquelle la chaîne est convertie. (REMARQUE : Cet avertissement sera toujours désactivé par défaut et ne doit être utilisé que pour localiser des problèmes potentiels).
Recommandations
- Conservez les fichiers source au format UTF-8
- Les fichiers peuvent rester ANSI aussi longtemps que le source est compilé avec la page de code correcte. Sélectionnez Projet > Options > Compilateur C++ > Options avancées et utilisez l'option "Page de code" sous Autres options pour définir la page de code correcte.
- Ecrivez un BOM UTF-8 dans le fichier source. Assurez-vous que le système de gestion du contrôle de source prend en charge ces fichiers.
- Effectuez un refactoring EDI quand le code doit être
AnsiString
ouAnsiChar
(code toujours portable). - Révision du code statique
- Le code passe t-il simplement les données ?
- Le code fait-il une simple indexation de caractères ?
- Tenez compte de tous les avertissements (élever en erreurs)
- Conversions de pointeur suspectes.
- Conversions implicites/explicites.
- Déterminez l'objectif du code
- Le code utilise t-il une chaîne (
AnsiString
) comme un tableau d'octets dynamique ? Dans ce cas, utilisez à la place le typeTBytes
portable (tableau deByte
). - Une conversion
PChar
est-elle utilisée pour activer l'arithmétique de pointeur ? Dans ce cas, convertissez plutôt enPByte
et effectuez l'activation$POINTERMATH ON
.
- Le code utilise t-il une chaîne (
Voir aussi
- Routines de conversion UTF-8
- Delphi Unicode Migration for Mere Mortals: Stories and Advice from the Front Lines, par Cary Jensen (EN)
- Delphi in a Unicode World Part I: What is Unicode, Why do you need it, and How do you work with it in Delphi? (EN)
- Delphi in a Unicode World Part II: New RTL Features and Classes to Support Unicode (EN)
- RAD Studio 2010 Migration Center (EN)
- Activation des applications pour Unicode
- Activation des applications C++ pour Unicode
- Mappage _TCHAR (C++)
- Utilisation d'Unicode dans la console de commandes
- Utilisation de TEncoding pour les fichiers Unicode
- Utilisation de TEncoding pour les fichiers Unicode
- Comment gérer la spécification de page de code AnsiString Delphi dans C++
- System.UnicodeString