IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

UTF8 dans une String de D10


Sujet :

Delphi

  1. #1
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut UTF8 dans une String de D10
    Bonjour,

    Première fois que je migre un projet D7 en D10 donc de ANSI vers UNICODE
    Jusqu'à présent, j'ai migré des bouts de code que j'avais écrit en D3 à D7 vers DXE2, je maîtrisais la fonction, la plupart du temps une lecture de fichier ANSI

    Mais je suis confronté à un problème

    Le code dont je dispose, à priori D7

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TxxxForm.btnxxxClick(Sender: TObject);
    begin
      memo.Text  := FonctionMaison(AnsiToUtf8(edInput.Text), TRUE);
    end;
    Exemple : 'é' devient 'é' puis FonctionMaison génère une chaine de longueur 12


    Même code en D10, on ignore le warning < W1057 Transtypage de chaîne implicite de 'RawByteString' en 'string' >

    Mais la problème
    Exemple : 'é' devient 'é' puis c'est reconverti en 'é' puis FonctionMaison génère une chaine de longueur 10

    Evidemment, avant, cela traitement deux caractères mais maintenant plus qu'un seul !

    Ce qui est encore plus surprenant c'est ceci
    on ignore les warnings très nombreux de conversion implicite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    var
      RBS8: RawByteString;
    begin
      RBS8 := UTF8Encode('é');
      Label5.Caption := 'String UTF8 : ' + RBS8;
      Label6.Caption :=  RBS8;
      ShowMessage(RBS8);
    Label5 affiche 'String UTF8 : é', ça c'est top ! exactement ce que je veux, cela conserve l'UTF8 sans le reconvertir, génial le LStrCat concatène la constante Ansi et ensuite c'est l'ensemble qui est converti de Ansi vers Unicode, ça me plait mais va exploiter cette étrangeté
    Label6 affiche 'é' ... ma question : comment désactiver la conversion implicite UTF8 vers UNICODE, je voudrais voir 'é' ?
    ShowMessage affiche 'é'

    Bon évidemment, j'ai trouvé une astuce mais il doit bien exister une syntaxe entre AnsiString, UTF8String, RawByteString, UnicodeString pour éviter ça


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      PStrRec(PByte(RBS8) - SizeOf(StrRec)).codePage := CP_ACP;
      Label8.Caption :=  RBS8;
      ShowMessage(RBS8);
    Label8 et ShowMessage affiche correctement mon 'é'

    Car oui, je veux passer à FonctionMaison qui ne doit pas être modifié, une chaine UTF8 dans une UnicodeString ...
    Donc pas de TBytes ni te TEncoding comme on le pratique avec les TStream

    Bon ça c'est si je veux que l'exe D10 et l'exe D7 fasse la même chose, mais je sais que j'ai découvert un loup bien méchant et que le chaperon Rouge que je suis va le manger !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Une très bonne piste justement TBytes !
    C'écrit à l'arrache mon PC Distant en TSC vient de rebooter comme un sauvage, encore Edge qui se met à jour comme une Merde !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memo.Text  := FonctionMaison(TEncoding.ANSI.GetString(TEncoding.UTF8.GetBytes(edInput.Text)), TRUE);
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Expert confirmé Avatar de sergio_is_back
    Homme Profil pro
    Responsable informatique, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable informatique, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 086
    Points : 5 607
    Points
    5 607
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Une très bonne piste justement TBytes !
    C'écrit à l'arrache mon PC Distant en TSC vient de rebooter comme un sauvage, encore Edge qui se met à jour comme une Merde !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memo.Text  := FonctionMaison(TEncoding.ANSI.GetString(TEncoding.UTF8.GetBytes(edInput.Text)), TRUE);
    Oui je te confirme que c'est la bonne façon de faire, j'ai déjà eu ce genre de mésaventure

  4. #4
    Membre expert
    Avatar de pprem
    Homme Profil pro
    MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Inscrit en
    Juin 2013
    Messages
    1 876
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 876
    Points : 3 611
    Points
    3 611
    Par défaut
    En fait "AnsiToUtf8" fait l'inverse de ce que tu voulais faire d'après le code que que tu as mis avec les GetBytes.

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par pprem Voir le message
    En fait "AnsiToUtf8" fait l'inverse de ce que tu voulais faire d'après le code que que tu as mis avec les GetBytes.
    Euh, non, j'ai bien le résultat que je cherche, récupérer la valeur brute en UTF8

    D7 avec AnsiToUtf8 : 'é' devient 'é' stocké dans une string (AnsiString, 2 Char = 2 Octets)
    D10 avec TEncoding.ANSI.GetString(TEncoding.UTF8.GetBytes : 'é' devient 'é' stocké dans une string (UnicodeString, 2 Char = 4 Octets)


    C'est AnsiToUtf8 en D10 qui n'est pas utilisable car la chaine RawByteString à un Code Page qui provoque une conversion lors de l'affectation à une variable UnicodeString, du coup on perd tout l'intérêt d'avoir encodé en UTF8
    Un seconc paramètre AnsiToUtf8 pour forcer soit UTF8 soit ANSI en CodePAge selon si l'on veut exploiter le texte ou la forme brute par la suite aurait été utile

    D7 ShowMessage(AnsiToUtf8('é')); affiche 'é'
    D10 ShowMessage(AnsiToUtf8('é')); affiche 'é' - comportement non souhaité < W1057 Transtypage de chaîne implicite de 'RawByteString' en 'string' >
    D10 ShowMessage(String(AnsiToUtf8('é'))); affiche 'é' - comportement non souhaité mais plus de warning
    D10 ShowMessage(String(PAnsiChar(AnsiToUtf8('é')))); affiche 'é' mais passer par un PAnsiChar pour générer un String c'est lourd mais c'est la syntaxe que je cherchais
    D10 MessageBoxA(0, PAnsiChar(AnsiToUtf8('é')), PAnsiChar(AnsiToUtf8('é')), MB_OK); affiche 'é'
    D10 ShowMessage(TEncoding.ANSI.GetString(TEncoding.UTF8.GetBytes('é'))); affiche 'é'


    Ceci aurait été intelligent et simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function AnsiToUtf8(const US: UnicodeString; Raw: Boolean = False): RawByteString;
    type
      PStrRec = ^StrRec;
      StrRec = packed record
        _Padding: Integer; // Make 16 byte align for payload..
        codePage: Word;
        elemSize: Word;
        refCnt: Integer;
        length: Integer;
      end;
    var
      L: Integer;
      Temp: UTF8String;
    begin
      Result := '';
      if US = '' then Exit;
      L := Length(US);
      SetLength(Temp, L * 3); // SetLength includes space for null terminator
     
      L := UnicodeToUtf8(PAnsiChar(Temp), Length(Temp) + 1, PWideChar(US), L);
      if L > 0 then
        SetLength(Temp, L - 1)
      else
        Temp := '';
      Result := Temp;
      if Result <> '' then
        PStrRec(PByte(Result) - SizeOf(StrRec)).codePage := IfThen(Raw, CP_ACP, CP_UTF8);
    end;
    D10 ShowMessage(String(AnsiToUtf8('é'))); affiche 'é' - Comportement simpliste pour la plupart des programmeurs qui ne pigent rien à Ansi, UTF8 et Unicode ...
    D10 ShowMessage(String(AnsiToUtf8('é', True))); affiche 'é' - Maitrise d'un UTF8 Brut volontaire, après tout c'est le but de RawByteString qui est RAW et pas UTF8 !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    Hello,

    alors déjà, il ne faut pas ignore les warnings, ils sont de très bons indices de ce qu'ils se passe, voir mon billet "Ne vous prenez pas les pieds dans les strings"

    la grosse différence avec 2009 c'est que les chaînes ont une page de code, avant la chaîne était juste un conteneur binaire bien pratique qui pouvait contenir de l'ANSI, de l'UTF8 ou de l'Unicode (avec des #0 entre les lettres)...avec 2009 une chaîne est vue comme une représentation d'un texte dans une page de code donnée...et affecter cette chaîne à un Caption va automatiquement la convertir en Unicode (puisque c'est un String unicode)

    par contre ton code m’interpelle...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      RBS8: RawByteString;
    begin
      RBS8 := UTF8Encode('é');
      ShowMessage(IntToStr(StringCodePage(RBS8)));
      Label1.Caption := 'String UTF8 : ' + RBS8;
      Label2.Caption :=  RBS8;
      ShowMessage(RBS8);
    end;
    StringCodePage donne 65001 donc ta RawByteString est en réalité une UTF8String, c'est pour cela que Label2 (ou 6 pour toi) est bon...ce qui m'étonne c'est la concaténation qui donne de l'UTF8 encodé...

    d'après ce que je comprend, 'String UTF8 :' est considéré comme une chaine ANSI non UTF8 et la concaténation d'une RawByteString se fait sans tester sa page de code, et du coup le résultat est une chaîne non UTF8 qui est ensuite transformée en Unicode avec une page de code 1252

    d'ailleurs si tu déclares RBS8 comme un UTF8String, tu as bien des "é" partout.

    c'est un effet de bord mais c'est logique en fait
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    alors déjà, il ne faut pas ignore les warnings, ils sont de très bons indices de ce qu'ils se passe, voir mon billet "Ne vous prenez pas les pieds dans les strings"
    Quand je parle d'ignorer les warnings, ce n'est pas à long terme, juste pour voir dans l'état ce que cela donne avant de faire par défaut un banal string(...) pour retirer le warning et avant trouver string(PAnsiChar(...)) il a fallu quelques essais, d'ailleurs, j'avais lu cet article, il y a bien longtemps.

    Citation Envoyé par Paul TOTH Voir le message
    la grosse différence avec 2009 c'est que les chaînes ont une page de code, avant la chaîne était juste un conteneur binaire bien pratique qui pouvait contenir de l'ANSI, de l'UTF8 ou de l'Unicode (avec des #0 entre les lettres)...avec 2009 une chaîne est vue comme une représentation d'un texte dans une page de code donnée...et affecter cette chaîne à un Caption va automatiquement la convertir en Unicode (puisque c'est un String unicode)
    Effectivement, c'est pour cela que l'ai bricolé comme indiqué dans mon ouverture de sujet PStrRec(PByte(RBS8) - SizeOf(StrRec)).codePage := CP_ACP; que l'on peut évidemment remplacer par un SetCodePage

    Citation Envoyé par Paul TOTH Voir le message
    par contre ton code m’interpelle...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      RBS8: RawByteString;
    begin
      RBS8 := UTF8Encode('é');
      ShowMessage(IntToStr(StringCodePage(RBS8)));
      Label1.Caption := 'String UTF8 : ' + RBS8;
      Label2.Caption :=  RBS8;
      ShowMessage(RBS8);
    end;
    StringCodePage donne 65001 donc ta RawByteString est en réalité une UTF8String, c'est pour cela que Label2 (ou 6 pour toi) est bon...ce qui m'étonne c'est la concaténation qui donne de l'UTF8 encodé...
    Oui en D7, la fonction retournait un UTF8String function AnsiToUtf8(const S: string): UTF8String; un type qui n'était qu'un alias à l'époque contrairement à maintenant
    J'ai aussi tenté UTF8String, AnsiString avant de poster, je ne trouvais pas le transtypage correct pour éviter la conversion, après j'ai tenté TEncoding mais je trouvais la syntaxe lourde enfin j'ai triché par le PAnsiChar pour qu'il traite la donnée brute sans sa méta-donnée.

    J'ai fait la même analyse, la constante est ANSI, cela utilise une LStrCat3 Ansi qui ignore le CodePage
    Citation Envoyé par ShaiLeTroll Voir le message
    ...le LStrCat concatène la constante Ansi et ensuite c'est l'ensemble qui est converti de Ansi vers Unicode...

    La manipulation volontaire d'UTF8 devient tout de même retord en D10.



    Sinon au final, semble que cet UTF8 est apparu en 2015 sur une version D7 d'un programme client qui n'était plus compatible avec la version DXE2/D10 des programmes serveur
    C'était une erreur (excès de Zèle) donc je n'ai même plus besoin de m'embêter avec tout ça
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Recherche particulière dans une string
    Par Franck66 dans le forum SL & STL
    Réponses: 3
    Dernier message: 27/09/2005, 15h24
  2. [C#]Comment executer du code qui se trouve dans une string ?
    Par freddyboy dans le forum Windows Forms
    Réponses: 4
    Dernier message: 28/02/2005, 16h31
  3. mettre un entier dans une string
    Par kinder29 dans le forum SL & STL
    Réponses: 14
    Dernier message: 14/02/2005, 11h54
  4. [DOM] sauver dans une String
    Par hocinema dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 28/09/2004, 21h44
  5. [Syntaxe] mettre des ' dans une string ?
    Par souch dans le forum Débuter
    Réponses: 4
    Dernier message: 14/08/2003, 16h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo