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

Web & réseau Delphi Discussion :

Comment connaître l'encodage d'un stream provenant d'un FTP ?


Sujet :

Web & réseau Delphi

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut Comment connaître l'encodage d'un stream provenant d'un FTP ?
    Bonjour à tous,

    Je galère depuis un moment sur un sujet qui doit être tout bête, même après avoir lu pas mal de chose sur le sujet.
    Je charge un flux sur un ftp avec Indy, tel qu'il m'a été conseillé précédemment pour le multiplateforme.
    Je charge ensuite ce flux dans un stringlist pour le traiter, ce qui ne me pose pas de problème.
    J'ai même trouvé comment transformer un string UTF8 en ANSI.
    Le problème c'est que je ne sais pas à l'avance si le fichier qui est sur le ftp est en ANSI ou en UTF8 (en tout cas pas d'unicode ... c'est déjà ça)
    Donc si c'est un flux en UTF8 et que je le convertis en ANSI tout va bien, mais si c'est un flux en ANSI et que je le convertis en ANSI à nouveau ça va pas !

    La seule information qui me manque c'est comment savoir si le TStringStream que je charge depuis le ftp est en UTF8 ou en ANSI ?
    Je n'ai pas trouvé la fonction magique qui me donnerait cette information me permettant de discriminer le traitement à effectuer.
    J'ai cherché dans le TEncoding du TStringStream, mais je n'ai rien trouvé de différent que je charge un fichier UTF8 ou un fichier ANSI ... j'ai dû mal chercher, ou alors ça se trouve ailleurs ?

    Merci d'avance et bien cordialement.

  2. #2
    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 614
    Points
    3 614
    Par défaut
    Le seul truc qui distingue des fichiers ANSI/UTF-8 est la présence du BOM comme premier caractère ou son absence.

    si ce caractère est à, c'est de l'UTF-8.
    S'il n'y est pas, il faut vérifier s'il y a des trucs chelous dans le fichier avant de considérer que c'est de l'ANSI car certains fichiers UTF-8 sont enregistrés sans BOM.

    Pas de fonction miracle pour ça malheureusement.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Merci pour cette réponse qui confirme mes craintes.
    Visiblement les fichiers en UTF8 que je dois traiter n'ont pas de BOM en début de fichier, pas de signature ...
    Ce qui me rassure c'est que j'ai compris, mais que les fichiers à traiter n'ont pas le discriminant désiré ... je ne sais pas comment font les logiciels pour comme notepad pour détecter que c'est de l'utf8 et pas de l'ANSI ?
    En fait, sur la vue en hexa, ce sont essentiellement les caractères accentués qui sont codés sur deux octets en UTF8 et 1 octet en ANSI.

    Je vais essayer de travailler là-dessus, mais je ne connais pas à l'avance le contenu du fichier ... :o(
    Il va falloir développer de l'intelligence artificielle ?

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 896
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 896
    Points : 11 452
    Points
    11 452
    Billets dans le blog
    6
    Par défaut
    Bonjour,
    D'après ce que j'ai lu, si c'est soit ANSI, soit UTF-8, c'est ANSI si tu trouves un caractère invalide en UTF-8...

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Oui merci c'est ce que je suis en train de faire.
    J'ai remarqué que tout les caractères accentués étaient codés sur 2 octets qui commencent par C3
    Je vais me baser là-dessus je crois...
    je vous tiens au courant ...

    EDIT : Bon ça marche très bien en détectant $C3 dans les fichiers UTF8, et s'il n'y en a pas ça veut dire qu'il n'y a pas de caractères accentués et dans ce cas là UTF8 = ANSI
    Donc pour l'instant je vais en rester là

    Merci à vous

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Citation Envoyé par pprem Voir le message
    Le seul truc qui distingue des fichiers ANSI/UTF-8 est la présence du BOM comme premier caractère ou son absence.

    si ce caractère est à, c'est de l'UTF-8.
    S'il n'y est pas, il faut vérifier s'il y a des trucs chelous dans le fichier avant de considérer que c'est de l'ANSI car certains fichiers UTF-8 sont enregistrés sans BOM.

    Pas de fonction miracle pour ça malheureusement.
    au fait tu voulais indiquer quelque chose après si ce caractère est à ?

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 693
    Points : 10 737
    Points
    10 737
    Par défaut
    Citation Envoyé par navyg Voir le message
    J'ai remarqué que tout les caractères accentués étaient codés sur 2 octets qui commencent par C3
    je pense que la meilleure approche est :

    Premièrement, il faut tester si ton caractère est supérieur strictement à 127 (0x7F).
    La table ASCII n'utilise que 127 caractères (7 bits sur 1 octet) et l'UTF-8 utilise cette caractéristique pour être compatible ASCII.

    Deuxièmement, si tu trouves 1 caractère non ASCII, tester si c'est 1 caractère UTF-8 valide (regarde la page wikipedia postée par @tourlourou)
    Là c'est 1 gros problème de l'UTF-8 notamment pour les bases de données : ce n'est pas 1 encodage fixe.
    Il faut :
    1. prendre 1 octet, tester s'il commence par 0x6 (sur 3 bits), 0xE (sur 4 bits) ou 0x1E (sur 5 bits et le 6ième bit soit 1 soit 0)
    2. extraire le codepoint avec les octets suivants - tester leur validité, commence par 0x2 sur 2 bits
    3. valider le codepoint avec la plage des valeurs


    peut-être qu'1 bibliothèque peut le faire pour toi.

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Hou là... ça me paraît bien complexe ...
    Je vais d'abord tester quelques fichiers avec ma méthode...

  9. #9
    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 : 55
    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 466
    Points
    28 466
    Par défaut
    voici la fonction que j'utilise

    elle regarde si les séquences de caractères > $7F sont compatible UTF8

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    function DetectUF8(Ptr: PByte; Size: Integer): Boolean;
    var
      Index: Integer;
      C1   : Byte;
      C2   : Byte;
      C3   : Byte;
    begin
      Result := False;
      C2 := 0; // UTF8Sequence not found
      Index := 0;
      while Index < Size do
      begin
      {
          $00..$7F
     
          $C2..$DF + $80..$BF
     
          $E0      + $A0..$BF + $80..$BF
          $E1..$EC + $80..$BF + $80..$BF
          $ED      + $80..$9F + $80..$BF
          $EE..$EF + $80..$BF + $80..$BF
     
          $F0      + $90..$BF + $80..$BF + $80..$BF
          $F1..$F3 + $80..$BF + $80..$BF + $80..$BF
          $F4      + $80..$8F + $80..$BF + $80..$BF
      }
        C1 := Ptr[Index];
        Inc(Index);
        case C1 of
          $00..$7F: { ASCII } ;
          $C2..$F4: // UTF8 compatible
          begin
            if Index = Size then
              Exit; // need a second byte
            C2 := Ptr[Index];
            if (C2 < $80) or (C2 > $BF) then
              Exit; // invalid UTF8 Sequence
            Inc(Index);
            if C1 >= $E0 then // more then 2 chars
            begin
              if Index = Size then // 3 chars sequence
                Exit;
              if (C1 = $E0) and (C2 < $A0) then
                Exit;
              if (C1 = $ED) and (C2 > $9F) then
                Exit;
              if (C1 = $F0) and (C2 < $90) then
                Exit;
              C3 := Ptr[Index];
              if (C3 < $80) or (C3 > $BF) then
                Exit; // invalid UTF8 Sequence
              Inc(Index);
              if C2 >= $F0 then
              begin
                if Index = Size then
                  Exit; // 4 chars sequence
                C3 := Ptr[Index];
                if (C3 < $80) or (C3 > $BF) then
                  Exit; // invalid UTF8 Sequence
                Inc(Index);
              end;
            end;
          end;
        else
          Exit(False); // UTF8 incompatible
        end;
      end;
      Result := C2 <> 0; // UTF8 compatible
    end;
    en paramètre j'utilise un PByte plus générique que AnsiString ou autre...tu peux par exemple faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var
      s: AnsiString;
    begin
      DetectUTF8(@s[1], Length(s));
    end;

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Merci Paul.
    Je regarde ça demain matin car à cette heure ci j'ai du mal.

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 789
    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 789
    Points : 25 777
    Points
    25 777

  12. #12
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    voici la fonction que j'utilise

    elle regarde si les séquences de caractères > $7F sont compatible UTF8

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    function DetectUF8(Ptr: PByte; Size: Integer): Boolean;
    var
      Index: Integer;
      C1   : Byte;
      C2   : Byte;
      C3   : Byte;
    begin
      Result := False;
      C2 := 0; // UTF8Sequence not found
      Index := 0;
      while Index < Size do
      begin
      {
          $00..$7F
     
          $C2..$DF + $80..$BF
     
          $E0      + $A0..$BF + $80..$BF
          $E1..$EC + $80..$BF + $80..$BF
          $ED      + $80..$9F + $80..$BF
          $EE..$EF + $80..$BF + $80..$BF
     
          $F0      + $90..$BF + $80..$BF + $80..$BF
          $F1..$F3 + $80..$BF + $80..$BF + $80..$BF
          $F4      + $80..$8F + $80..$BF + $80..$BF
      }
        C1 := Ptr[Index];
        Inc(Index);
        case C1 of
          $00..$7F: { ASCII } ;
          $C2..$F4: // UTF8 compatible
          begin
            if Index = Size then
              Exit; // need a second byte
            C2 := Ptr[Index];
            if (C2 < $80) or (C2 > $BF) then
              Exit; // invalid UTF8 Sequence
            Inc(Index);
            if C1 >= $E0 then // more then 2 chars
            begin
              if Index = Size then // 3 chars sequence
                Exit;
              if (C1 = $E0) and (C2 < $A0) then
                Exit;
              if (C1 = $ED) and (C2 > $9F) then
                Exit;
              if (C1 = $F0) and (C2 < $90) then
                Exit;
              C3 := Ptr[Index];
              if (C3 < $80) or (C3 > $BF) then
                Exit; // invalid UTF8 Sequence
              Inc(Index);
              if C2 >= $F0 then
              begin
                if Index = Size then
                  Exit; // 4 chars sequence
                C3 := Ptr[Index];
                if (C3 < $80) or (C3 > $BF) then
                  Exit; // invalid UTF8 Sequence
                Inc(Index);
              end;
            end;
          end;
        else
          Exit(False); // UTF8 incompatible
        end;
      end;
      Result := C2 <> 0; // UTF8 compatible
    end;
    en paramètre j'utilise un PByte plus générique que AnsiString ou autre...tu peux par exemple faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var
      s: AnsiString;
    begin
      DetectUTF8(@s[1], Length(s));
    end;
    Tout d'abord, merci pour ce code très complexe (mais limpide une fois que tu y regardes de plus près) qui m'éclaire sur la méthode à employer, mais que j'ai eu du mal à mettre en oeuvre ;o)
    Premièrement, j'ai cherché quelques secondes (heu ... peut-être minutes ...) pourquoi, après avoir copier/coller ton exemple de fonction l'utilisation de DetectUTF8 dans le code me faisait une erreur de syntaxe. Et puis en relisant attentivement, j'ai vu que la fonction se nommait DetectUF8 ... sans le T entre U et F ;o)
    Après correction je me heurte au fait que l'exemple indique une utilisation sur une AnsiString, alors que je voudrais le tester sur un TStringStream.
    Là aussi, après quelques recherches, j'arrive à trouver la bonne syntaxe, permise je pense par l'utilisation du Pbyte, justement très générique comme tu l'indiques.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    var 
       MyStringStream: TStringStream,
     
    begin
    DetectUTF8(MyStringStream.Memory, MyStringStream.size);
    end;
    Alors que pour s qui est une AnsiString dans ton exemple, il faut utiliser le @ pour indiquer un pointeur vers s, la propriété Memory du TStringStream est déjà un pointeur, donc pas de @.

    J'ai donc mis en oeuvre ta fonction, beaucoup plus complète, et qui me semble par ailleurs plus rapide que ma boucle par le read du TStringSream ...

    Merci encore au forum !

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 789
    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 789
    Points : 25 777
    Points
    25 777
    Par défaut
    TStringStream sur un Delphi Unicode ?
    Memory pointe sur une zone mémoire dont l'encodage varie selon TEncoding (par défaut ANSI en Windows, UTF8 en Linux)

    j'ai lu au début " pour le multiplateforme " donc attention aux effets de bord de fonction fait les conversion via TEncoding

    Et le Read du TStringStream, hérité du TMemoryStream, qui contiendrait du UTF8 en brut, ça lit la donnée brute
    Par contre ReadString lui converti la donnée brute en fonction du TEncoding vers une UnicodeString.

    La fonction standard IsUTF8String fonctionne sur une RawByteString, dommage comme celle de Paul, PByte ou PAnsiChar aurait été plus ouvert (surtout le la première chose faite par la fonction c'est d'obtenir le pointeur sur la chaine s passée en paramètre)

    Pour la passage en TStringList, je te recommande :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if DetectUTF8(MyStringStream.Memory, MyStringStream.size) then
      MyStringList.LoadFromStream(MyStringStream, TEncoding.UTF8)
    else
      MyStringList.LoadFromStream(MyStringStream, TEncoding.ANSI)
    D'ailleurs MyStringStream pourait être un TMemoryStream seulement pour la lecture FTP pour éviter tout tentation d'utilisé le mode String du TStringStream.

  14. #14
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Alors, j'ai testé, mais la fonction de Paul permet de l'appliquer directement sur TstringStream, alors que la fonction IsUTF8String attend un RawByteString (qui est en fait une AnsiString sans utilisation de l'encodage si j'ai bien compris) en paramètre.
    Et lorsqu'on définit une RawByteString, il est indiqué AnsiString(65535) ... limitée à 65535 caractères ?
    Dans l'unité System, le type RawByteString est défini comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    RawByteString = type _AnsiString($ffff);
    Cela induit une limite ?

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 789
    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 789
    Points : 25 777
    Points
    25 777
    Par défaut
    C'est le CodePage et non la taille

    Oui comme je l'ai écrit, je déplore aussi que IsUTF8String utilise une RawByteString, c'est peu pratique

  16. #16
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    TStringStream sur un Delphi Unicode ?
    Memory pointe sur une zone mémoire dont l'encodage varie selon TEncoding (par défaut ANSI en Windows, UTF8 en Linux)

    j'ai lu au début " pour le multiplateforme " donc attention aux effets de bord de fonction fait les conversion via TEncoding

    Et le Read du TStringStream, hérité du TMemoryStream, qui contiendrait du UTF8 en brut, ça lit la donnée brute
    Par contre ReadString lui converti la donnée brute en fonction du TEncoding vers une UnicodeString.

    La fonction standard IsUTF8String fonctionne sur une RawByteString, dommage comme celle de Paul, PByte ou PAnsiChar aurait été plus ouvert (surtout le la première chose faite par la fonction c'est d'obtenir le pointeur sur la chaine s passée en paramètre)

    Pour la passage en TStringList, je te recommande :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if DetectUTF8(MyStringStream.Memory, MyStringStream.size) then
      MyStringList.LoadFromStream(MyStringStream, TEncoding.UTF8)
    else
      MyStringList.LoadFromStream(MyStringStream, TEncoding.ANSI)
    D'ailleurs MyStringStream pourait être un TMemoryStream seulement pour la lecture FTP pour éviter tout tentation d'utilisé le mode String du TStringStream.
    Le code ci-dessus est la première chose que j'avais essayé, sans test, sur un fichier que je savais être en UTF8 mais ça n'avait pas marché ... les caractères bizarres apparaissaient toujours bizarres .. car j'avais mal compris ce qu'il fallait faire !
    En fait je mettais TEncoding.ANSI pour forcer le passage en ANSI, mais je viens de comprendre en lisant ton post qu'il faut indiquer le TEncoding de la source !
    Et là ça fonctionne très bien.

    Qu'est ce que je suis c... ou tout simplement vieux !

    En ce qui concerne le TStringStream, c'est simplement que ça m'avait paru plus pratique pour un fichier texte. Pour les autres fichiers, je charge dans un Tmemorystream effectivement.

    Merci encore à tous de vos conseils ... l'union fait la force, mais l'oignon fait la soupe ... je sors

    ET Finalement, en relisant une partie de ton post :
    Citation Envoyé par ShaiLeTroll Voir le message
    ...
    La fonction standard IsUTF8String fonctionne sur une RawByteString, dommage comme celle de Paul, PByte ou PAnsiChar aurait été plus ouvert (surtout le la première chose faite par la fonction c'est d'obtenir le pointeur sur la chaine s passée en paramètre)
    ...
    je me suis dis pourquoi pas ? J'ai donc pompé le code des fonctions ci-dessus et l'ai modifié à la "sauce" Paul, ce qui donne une fonction directement utilisable avec un stream :
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
     
       // Detect valid UTF8 sequence.
       // function DetectUTF8Encoding(const s: RawByteString): TEncodeType;      original
       function DetectUTF8Encoding_p(P: Pbyte; size: Integer): TencodeType;
       var
         c : Byte;
         //P,
         EndPtr: PByte;
       begin
         Result := etUSASCII;
         //P := PByte(PAnsiChar(s));
         //EndPtr := P + Length(s);
     
         EndPtr := P + size;
     
         // skip leading US-ASCII part.
         while P < EndPtr do
         begin
           if P^ >= $80 then break;
           inc(P);
         end;
     
         // If all character is US-ASCII, done.
         if P = EndPtr then exit;
     
         while P < EndPtr do
         begin
           c := p^;
           case c of
             $00..$7F:
               inc(P);
     
             $C2..$DF:
               if (P+1 < EndPtr)
                   and ((P+1)^ in [$80..$BF]) then
                 Inc(P, 2)
               else
                 break;
     
             $E0:
               if (P+2 < EndPtr)
                   and ((P+1)^ in [$A0..$BF])
                   and ((P+2)^ in [$80..$BF]) then
                 Inc(P, 3)
               else
                 break;
     
             $E1..$EF:
               if (P+2 < EndPtr)
                   and ((P+1)^ in [$80..$BF])
                   and ((P+2)^ in [$80..$BF]) then
                 Inc(P, 3)
               else
                 break;
     
             $F0:
               if (P+3 < EndPtr)
                   and ((P+1)^ in [$90..$BF])
                   and ((P+2)^ in [$80..$BF])
                   and ((P+3)^ in [$80..$BF]) then
                 Inc(P, 4)
               else
                 break;
     
             $F1..$F3:
               if (P+3 < EndPtr)
                   and ((P+1)^ in [$80..$BF])
                   and ((P+2)^ in [$80..$BF])
                   and ((P+3)^ in [$80..$BF]) then
                 Inc(P, 4)
               else
                 break;
     
             $F4:
               if (P+3 < EndPtr)
                   and ((P+1)^ in [$80..$8F])
                   and ((P+2)^ in [$80..$BF])
                   and ((P+3)^ in [$80..$BF]) then
                 Inc(P, 4)
               else
                 break;
           else
             break;
           end;
         end;
     
         if P = EndPtr then result := etUTF8
         else result := etANSI;
     
       end;
     
       // if string contains real UTF8 character, return true.
       //function IsUTF8String(const s: RawByteString): Boolean;              original
       function IsUTF8String_p(const p: Pbyte; size: Integer): Boolean;
       begin
         result := DetectUTF8Encoding_p(p, size) = etUTF8;
       end;
    C'est une cagade ? ou bien ...?
    En tout cas sous windows ça marche

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    C'est le CodePage et non la taille

    Oui comme je l'ai écrit, je déplore aussi que IsUTF8String utilise une RawByteString, c'est peu pratique
    Ok merci pour la précision pour le codepage
    Pour le IsUTF8String, avec mon post ci-dessus peut-être que le problème est résolu et la fonction modifiée rend l'utilisation plus simple non ?

  18. #18
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 789
    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 789
    Points : 25 777
    Points
    25 777
    Par défaut
    En plus tu as plein de fonction orienté Stream dans WideStrUtils mais pas IsUTF8Stream ou IsUTF8Bytes ... surtout ce dernier le TBytes étant très utilisé avec TEncoding, cela semblerait être la forme idéale
    TStringStream étant un TBytesStream donc supporte le TBytes, j'utilise plus souvent un TBytesStream qu'un TMemoryStream à cause de cette portabilité

  19. #19
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    400
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 400
    Points : 171
    Points
    171
    Par défaut
    Tout à fait d'accord.
    Merci.

  20. #20
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 789
    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 789
    Points : 25 777
    Points
    25 777
    Par défaut
    Autre approche pour utiliser DetectUTF8Encoding original c'est de faire sa variante de MemoryStream (plus difficile de gérer un tampon qui grossit par packet avec une RawByteString, donc ça peut etre plus lent si le tampon de lecture est inférieur à 2Ko)


    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
    type
      TRawByteStringStream = class(TMemoryStream)
      private
        type
          TMemoryStreamHack = class(TCustomMemoryStream)
          private
            FCapacity: Longint;
          end;
      private
        FRBS: RawByteString;
      protected
        function Realloc(var NewCapacity: Longint): Pointer; override;
      public
        constructor Create(const AString: RawByteString); overload;
        property RBS: RawByteString read FRBS;
      end;
    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
    constructor TRawByteStringStream.Create(const AString: RawByteString);
    begin
      inherited Create;
      FRBS := AString;
      SetPointer(Pointer(AString), Length(AString));
      TMemoryStreamHack(Self).FCapacity := Size;
    end;
     
    function TRawByteStringStream.Realloc(var NewCapacity: Longint): Pointer;
    begin
      if NewCapacity <> Size then
      begin
        SetLength(FRBS, NewCapacity);
        Result := Pointer(FRBS);
        if NewCapacity = 0 then
          Exit;
        if Result = nil then
          raise EStreamError.Create('Out of memory while expanding RawByteString stream');
      end
      else
        Result := Pointer(FRBS);
    end;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if IsUTF8String(MyRawByteStringStream.RBS) then
      MyStringList.LoadFromStream(MyRawByteStringStream, TEncoding.UTF8)
    else
      MyStringList.LoadFromStream(MyRawByteStringStream, TEncoding.ANSI)

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 9
    Dernier message: 18/11/2010, 15h51
  2. Comment connaître l'encodage d'un fichier texte?
    Par sergentgarcia dans le forum Général Python
    Réponses: 3
    Dernier message: 26/05/2008, 11h41
  3. Réponses: 5
    Dernier message: 15/04/2004, 14h24
  4. Comment connaître son IP derrière un routeur ?
    Par momox dans le forum C++Builder
    Réponses: 2
    Dernier message: 22/02/2004, 19h24
  5. Comment connaître le nom de l'ordinateur ?
    Par M.Dlb dans le forum API, COM et SDKs
    Réponses: 3
    Dernier message: 31/08/2003, 00h03

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