2017-10-19 20 views
1

La technique recommandée pour la lecture des fichiers UTF-8 est:Lire UTF-8 fichier codé qui comprend encodages 4 octets dans Excel

Dim FileStream As Stream 
    Dim FileBodyADO As String 

    Set FileStream = CreateObject("ADODB.Stream") 

    With FileStream 
    .Charset = "utf-8" 
    .Open 
    .LoadFromFile ("C:\DataArea\Resources\VBA Outlook\Tutorial\examples.json") 

    FileBodyADO = .ReadText() 

    .Close 
    End With 

    Set FileStream = Nothing 

Toutefois, si vous essayez de lire « examples.json » qui fait partie de la documentation SO archivée, l'instruction FileBodyADO = .ReadText() ne se termine jamais.

Un fichier UTF-8 est un octet fichier orienté (contrairement, par exemple, UTF-16) avec des caractères dont les codes sont dans la gamme de 0 à & H7F effectuée inchangé et des caractères avec des codes ci-dessus & H7F codés à plusieurs octets séquences:

-Code (Hex)- ---------------Encoding--------------- 
    Start End Byte 1 Byte 2 Byte 3 Byte 4 
     0  7F 0xxxxxxx 
    80 7FF 110xxxxx 10xxxxxx 
    800 FFFF 1110xxxx 10xxxxxx 10xxxxxx 
    10000 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

« examples.json » contient:

92,601,220 1-byte encodings 
    8,848 2-byte encodings 
    20,122 3-byte encodings and 
     166 4-byte encodings. 

Les codages de 1 octet sont des caractères ASCII. Les codages sur 2 octets sont, par exemple, § (HA7) et I (H131). Les codages à 3 octets sont, par exemple, √ (H221A) et 年 (H5E74). Les codages de 4 octets sont, par exemple, "Coeur étincelant" (H1F496) et "Visage souriant avec des yeux souriants" (H1F601).

Je ne trouve rien qui puisse suggérer que les produits Office puissent gérer des caractères avec des codes au-dessus de U + FFFF. Je soupçonne que ReadText se termine par une boucle sans fin quand il frappe un encodage de 4 octets. J'ai mon propre programme VBA pour décoder un fichier UTF-8. Il a également échoué à traiter les encodages de 4 octets lorsqu'ils ont été rencontrés pour la première fois. Depuis, j'ai amélioré/corrigé ma routine pour accepter les encodages de 4 octets et les décoder comme des entités de caractères numériques. Par exemple, "Sourire avec des yeux souriants" (H1F601) est porté dans le fichier sous HF0 9F 98 81 que ma routine décode à 😁. Si cette entité de caractères numériques est placée dans un fichier html, Microsoft Edge affiche l'emoji correct. Je comprends Google Chrome et la plupart (tous?) Les navigateurs modernes peuvent également gérer de telles entités de caractères numériques. Que pouvez-vous voir: & # x01F601 ;? Puisque le texte qui inclut ces caractères est html, ma solution est adéquate pour mes besoins actuels.

Je posterai ma routine sous forme de réponse dans quelques jours à moins qu'une meilleure réponse ne soit postée en premier. Est-ce que les gens sont d'accord que ReadText ADODB est vaincu par des codages de 4 octets? Les produits Office, en particulier Excel, peuvent-ils gérer les caractères Unicode Plane 1 (H10000 à H1FFFF)? Existe-t-il une alternative à mon utilisation du caractère numérique?

Plus fond

J'ai accepté la réponse de Tom Blodget parce qu'il ne répond à ma question. Cependant, ce n'est pas la réponse que j'espérais.

Il y a quelques années, je recevais des fichiers dans différents formats incluant UTF-16, UTF-8, ASCII et ISO-8859-1. Les auteurs de ces fichiers extrayaient des données provenant de différentes applications mais j'ai trouvé la variété de formats inattendue; dans mon expérience, la plupart des applications utilisent UTF-8 ces jours-ci. Aucun de mes fournisseurs ne connaissait le format de leur application source ni comment changer le format de sortie en UTF-8 ou quelque chose de cohérent. "VBA traditionnel" lit ou écrit des fichiers ASCII ou Unicode (par lesquels Microsoft signifie OCS-2). Apparemment OCS-2 est "pratiquement identique" à UTF-16. Pour moi, "pratiquement identique" signifie différent mais je ne trouve rien pour expliquer comment ils diffèrent. ADODB est une bibliothèque VBA qui acceptera d'autres formats mais toute la documentation implique que vous deviez savoir ce qu'est ce format. Des utilitaires comme NotePad ++ ouvriront n'importe quel fichier texte et vous indiqueront son format. Je n'ai rien trouvé de similaire avec VBA.

J'ai décidé que je devais écrire mon propre code pour lire chaque fichier dans un tableau d'octets et identifier le format. Identifier le format n'était pas beaucoup moins de travail que l'identification et la conversion à une chaîne VBA, c'est ce que j'ai fait. Les fichiers n'étaient pas particulièrement volumineux, donc la lecture et la conversion prenaient moins de 0,01 seconde, ce qui était suffisant pour mes besoins.

Quand j'avais besoin de lire "examples.json", j'ai naturellement utilisé ma routine. Je sais maintenant que "examples.json" contient 166 encodages à 4 octets et que ma routine ne les gère pas correctement. J'ai corrigé les bugs dans ma routine et j'étais content du résultat, sauf qu'il a fallu 34 secondes avec la dernière version pour traiter le fichier 92Mb. J'ai essayé ADODB pour voir à quel point c'était plus rapide mais ça ne s'est jamais terminé. C'était jusqu'où j'avais été avant que je pose cette question. J'avais lu que ADODB n'était pas très efficace et que vous devriez lire un petit bloc à la fois. Cependant, je n'ai pas assimilé «inefficace» à «ne se termine pas» avant d'avoir essayé la réponse de Tom Blodget. En optimisant l'utilisation de ADODB comme suggéré, il a maintenant terminé. L'étude de la sortie a augmenté ma compréhension de l'encodage UTF-8, donc c'était un exercice utile. Cependant, à environ 40 secondes, ADODB était encore plus lent que ma routine VBA.

Sur mon ordinateur portable, le code suivant lit le fichier entier de 92 Mb dans un tableau d'octets en environ 0,1 secondes:

FileNum = FreeFile 
    Open PathFileName For Binary Access Read As FileNum 
    ReDim FileBodyByte(1 To LOF(FileNum)) 
    Get FileNum, , FileBodyByte 
    Close FileNum 

Une fois dans un tableau d'octets, la conversion à une chaîne est totalement liés au processeur. Pourquoi ADODB a-t-il besoin que le bloc soit lu dans des blocs de 128K? Que se passe-t-il si un bloc se termine au milieu d'un encodage? Pourquoi cela prend-il autant de temps? J'ai converti les routines VBA liées au processeur à VB.Net et j'ai réduit les durées d'un facteur de 1000. Je ne me sentirais pas à l'aise d'utiliser ADODB est une routine que j'ai libéré à un client.

Microsoft semble être obsédé par la compatibilité ascendante. Le code VBA que j'ai écrit il y a 15 ans fonctionne toujours. Microsoft n'améliore pas les vieilles routines; il introduit de nouvelles bibliothèques si de nouvelles fonctionnalités doivent être fournies. ADODB est vieux. J'espérais quelque chose de nouveau et de meilleur plutôt qu'une solution de rechange.

+0

Non, ADODB.Stream poignées de caractères UTF-8 codé avec 4 unités de code très bien. Le problème semble être quelque chose d'autre, peut-être la taille du fichier. –

Répondre

0

ADODB.Stream. La documentation ReadText explique un problème d'efficacité et propose de lire moins d'octets à la fois pour l'atténuer.

Ainsi,

Dim FileStream As Stream: Set FileStream = CreateObject("ADODB.Stream") 

    With FileStream 
    .Charset = "utf-8" 
    .Open 
    .LoadFromFile "C:\Users\Tom\Downloads\examples.json" 

    Dim FileBodyADO As String: FileBodyADO = "" 
    While Not .EOS 
     FileBodyADO = FileBodyADO & .ReadText(128 * 1024&) 
    Wend 
    Debug.Print Len(FileBodyADO) 
    Debug.Assert Len(FileBodyADO) = 92630322 
    .Close 
    End With 

    Set FileStream = Nothing 

Comme .NET vous indique indépendamment, examples.json contient du texte UTF-16 avec code 92630322 unités de code. (VBA/VB4 + utilise UTF-16 cordes [comme tant d'autres langues depuis le début des années 1990].)

File.ReadAllText(@"C:\Users\Tom\Downloads\examples.json").Length == 92630322 
+0

J'ai considéré les problèmes d'efficacité mais je les ai rejetés comme raison. J'ai quitté 'ADODB.ReadText' pendant une heure avant de l'annuler. Ma routine VBA prend 28 secondes pour décoder ce fichier 92Mb. Je m'attendrais à ce que 'ADODB.ReadText' soit plus rapide. À quoi 'ADODB.ReadText' décoderait-il les encodages de 4 octets? Je ne trouve aucune documentation qui indique/suggère/suggère qu'une chaîne VBA ou une chaîne Excel peut contenir des caractères avec des codes supérieurs à U + 10000. La documentation que j'ai trouvée recommande de conserver un emoji en tant qu'image si vous le souhaitez dans Excel. Veuillez faire un lien vers la documentation appropriée si vous savez différemment. –

+0

Je vais expérimenter avec votre code. Si cela fonctionne pour moi, je vais essayer de découvrir ce que les encodages de 4 octets ont décodé. Mon nombre de points de code était supérieur à la valeur obtenue, bien que cela puisse être une erreur dans mon code pour les compter. Cela dit, multiplier mes comptes par des longueurs d'encodage donne la bonne longueur de fichier. –

+0

Microsoft avait tendance à appeler le codage USC-2 du jeu de caractères Unicode "Unicode", puis à l'appliquer à son remplacement, UTF-16. La différence entre USC-2 et UTF-16 n'est pas typiquement un problème de langue ou de bibliothèque. La documentation [ChrW] (https://msdn.microsoft.com/fr-fr/vba/language-reference-vba/articles/chr-function) est difficilement interprétable et le terme "caractère" est ambigu, mais ChrW ne traite que d'un Unité de code UTF-16; Mettez deux ensemble dans une chaîne comme nécessaire pour un codepoint> U + FFFF et vous avez terminé. –