Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour j'ai un problème de conversion inexpliquée du caractère €.
Le programme que je corrige écrit fichier XML, via pbdom et via la commande
i_doc.SaveDocument(ls_fichier_txt+'SND.XML')
Jusque là tout va bien.
Voici ce que j'ai dans mon fichier : <maxPrestation>1500 €</maxPrestation>
Ensuite, et ne me demandez pas pourquoi, on réouvre le fichier, on le lit, afin d'avoir une string XML.
// Relire le xml (seule manière de l'avoir en string) ls_work = '' ld_return = FileOpen(ls_fichier_txt+'SND.XML',LineMode!,Read!) ld_file_in = ld_return DO UNTIL ld_return < 0 ld_return = FileRead(ld_file_in,ls_return) IF ld_return >= 0 THEN ls_work+= ls_return END IF LOOP FileClose(ld_file_in)
Là est mon problème, voici ce que j'ai dans ma string : <maxPrestation>1500 €</maxPrestation>
Le problème vient donc du fileopen ou du fileread.
On trafique le XML via
ls_work = f_global_replace(ls_work,'§',' ') // - pour ne pas tronquer les derniers espaces ls_work = f_global_replace(ls_work,'XxMmLl','XML') // - parce que le nom ne peut pas commencer par (ni être) XML ls_work = f_global_replace(ls_work,'xXmMlL','xml') // pour avoir en minuscule plutot qu'en majuscule ls_work = f_utf8_to_ansi(ls_work) // - on dit que c'est de l'UTF-8 et il y a des caractères accentués
Que dois-je faire pour récupérer le caractère exact ????
Y a t'il une commande à rajouter pour continuer à "trafiquer" le xml ???
Merci beaucoup
Dernière modification par Sylvie de hannut (05-03-2014 09:28:32)
Hors ligne
Bonjour,
Est ce que ton fichier contient le problème de caractère lorsque tu l'ouvre en dehors de ton appli?
Et pourquoi la relecture du fichier ne se fait pas par les PBDOM étant donné que l'écriture du fichier ce module
pbdom_document =pbdom_builder.buildfromfile('mon_fichier.xml')
Dernière modification par Van (04-03-2014 08:46:16)
Hors ligne
Bonjour,
ce n'est pas un problème d'encoding ? Le FileOpen prend le EncodingANSI! par défaut et il semble que le SaveDocument() prenne le utf16-le. Je creuserais de ce côté...
Hors ligne
Van, avec le
pbdom_document =pbdom_builder.buildfromfile('mon_fichier.xml')
J'ai le contenu du fichier dans une string ???
Geo, je vais creuse de ce côté là, merci
Dernière modification par Sylvie de hannut (04-03-2014 13:49:31)
Hors ligne
Non tu récupère le fichier dans un objet pbdom_document.
Ensuite tu navigue dedans avec les fonctions et objets PBDOM.
Hors ligne
il y a un tutorial vidéo si ça peut aider
Hors ligne
Van ça ne me conviens pas car apparemen ton trafique encore le tout.
Voilà tout le code, attention tout est historique et me semble très torturé ...
// Sauver tout le xml... IF uf_nvl(iubs_interface.is_com_recup) <> '' THEN iubs_interface.id_com+= 1 ls_fichier_txt = iubs_interface.is_com_recup + '\' & + STRING(iubs_interface.id_poste,'000') + '-' & + iubs_interface.is_programme + '-' + STRING(ToDay(),'yyyymmdd-hhmmss') + '-' + STRING (iubs_interface.id_com) + '-' ELSE MessageBox(uf_lib_langue('Attention - pas envoyé|Opgelet - niet gestuurd'),uf_lib_langue('Impossibilité sauvetage demande : vérifier existence répertoire et accessibilité svp'),Exclamation!,Ok!,1) iubs_interface.istr_downloadfiles[1].filename = '' iubs_interface.istr_downloadfiles[1].xmlcontent = '' RETURN -1 // ...ou dans Mes Documents ld_return = RegistryGet('HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders','Personal',RegString!,ls_return) IF uf_nvl(ls_return) = '' THEN ls_fichier_txt = '' ELSE ls_fichier_txt = ls_return + '\' END IF ls_fichier_txt += 'temp' END IF i_doc.SaveDocument(ls_fichier_txt+'SND.XML') [b]===> Quand je vais lire le fichier il est correct[/b] // Relire le xml (seule manière de l'avoir en string) ls_work = '' ld_return = FileOpen(ls_fichier_txt+'SND.XML',LineMode!,Read!) ld_file_in = ld_return DO UNTIL ld_return < 0 ld_return = FileRead(ld_file_in,ls_return) IF ld_return >= 0 THEN ls_work+= ls_return END IF LOOP FileClose(ld_file_in) // trafiquer le xml : ls_work = f_global_replace(ls_work,'§',' ') // - pour ne pas tronquer les derniers espaces ls_work = f_global_replace(ls_work,'XxMmLl','XML') // - parce que le nom ne peut pas commencer par (ni être) XML ls_work = f_global_replace(ls_work,'xXmMlL','xml') // pour avoir en minuscule plutot qu'en majuscule ls_work = f_utf8_to_ansi(ls_work) // - on dit que c'est de l'UTF-8 et il y a des caractères accentués iubs_interface.istr_downloadfiles[1].filename = ls_work IF iubs_interface.istr_downloadfiles[1].filename = '' THEN iubs_interface.istr_downloadfiles[1].xmlcontent = '' MessageBox(uf_lib_langue('Attention - pas envoyé|Opgelet - niet gestuurd'),& uf_lib_langue('Impossibilité sauvetage demande : vérifier existence répertoire et accessibilité svp'),Exclamation!,Ok!,1) ELSE IF uf_nvl(iubs_interface.is_com_recup) <> '' THEN ls_work = iubs_interface.iu_carrefourcompbni_service.indentxml(ls_work) ls_work = f_global_replace(ls_work,'utf-16','iso-8859-1') ld_return = FileOpen(ls_fichier_txt+'SND.XML',StreamMode!,Write!,LockWrite!,Replace!) DO WHILE LEN(ls_work) > 0 FileWrite(ld_return,ls_work) ls_work = MID(ls_work,32766) LOOP FileClose(ld_return) [b]===> Quand je vais lire le fichier il n' est plus correct[/b] END IF
Il faut savoir que ce code existe depuis plus de 10 ans et qu'il fonctionne très bien, mais pas avec le caractère "€".
Que puis-je faire pour que mon fichier soit encore bon pour l'existant mais qu'il soit bon également pour les nouveautés ???
Dernière modification par Sylvie de hannut (04-03-2014 13:49:52)
Hors ligne
Pour information : "€" (ou dans un éditeur hexa E2 82 AC) c'est le caractère "€" codé en utf-8, alors que "€" c'est ce que tu vois si tu réouvres en ansi un fichier texte contenant l'euro qui aurait été sauvé en utf-8.
Il faut bien que tu regardes du côté d'un prolème d'encodage qui ne serait pas le même à la lecture qu'à l'écriture
Petite question au passage, au vu du commentaire "Relire le xml (seule manière de l'avoir en string)", tu n'aurais pas simplement besoin de la méthode
pb_doc.SaveDocumentIntoString( )
?
Dernière modification par seki (04-03-2014 09:17:37)
Hors ligne
J'ai trouvé ceci dans l'aide
Handling ANSI data Since this function does not have an encoding argument to allow you to specify the encoding of the data, the string returned can contain garbage characters if the data has ANSI encoding. You can handle this by converting the ANSI string returned from the String function to a Unicode blob, and then converting the ANSI string in the blob to a Unicode string, using the encoding parameters provided in the Blob and String conversion functions: ls_temp = String(long, "address" ) lb_blob = blob(ls_temp) //EncodingUTF16LE! is default ls_result = string(lb_blob, EncodingANSI!)
J'ai essayé, mais EncodingANSI! ne passe pas à la compilation
Dernière modification par Sylvie de hannut (04-03-2014 13:50:10)
Hors ligne
Si je comprend bien, il faut que je convertisses ma string en UTF-16 ????
Ou alors que j'arrive à ouvrir le fichier en UTF-16 ????
Heuuu, comment fait-on pour convertir un string dans un autre format, ou ouvrir un fichier autrement ?
J'y connais rien en terme d'encodage de fichier, désolée
Ce qui serait bien, c'est que je récupère dans une string temporaire ce qui se trouve dans mon fichier xml de base avant l'écriture de calui-ci.
Mais comment faire pour mettre dans une string mon document pbdom ????
Dernière modification par Sylvie de hannut (04-03-2014 09:31:00)
Hors ligne
Sylvie de hannut a écrit:
On trafique le XML via
Code: = PB
... ls_work = f_utf8_to_ansi(ls_work) // - on dit que c'est de l'UTF-8 et il y a des caractères accentués
à moins que la personne qui a codé la fonction f_utf8_to_ansi() ne soit un farceur, le résultat est le contraire de ce qui est dit dans le commentaire : cette ligne convertit de l'utf-8 vers de l'ansi, ce qui explique très bien pourquoi tu obtiens "€" au lieu de "€"
Hors ligne
Seki a écrit : à moins que la personne qui a codé la fonction f_utf8_to_ansi() ne soit un farceur, le résultat est le contraire de ce qui est dit dans le commentaire : cette ligne convertit de l'utf-8 vers de l'ansi, ce qui explique très bien pourquoi tu obtiens "€" au lieu de "€"
En fait non, j'ai déjà ces caractères avant la conversion, je les ai dès la lecture du fichier.
En allant plus loin en debug, j'ai vérifié si un de ces trafiquage n'arrangeait pas les choses, mais non
Alors je cherche comment encore trafiquer le truc pour rajouter le €
Voici le code de la fonction f_utf8 to ansi
string new,c,c2 long i,l,ll_ascii if isnull(as_string) then return as_string l=len(as_string) for i=1 to l c=mid(as_string,i,1) choose case c case "Ã","Â" if i<l then c2=mid(as_string,i+1,1) ll_ascii=asc(c2) if c="Ã" and ll_ascii < 192 then c=char(ll_ascii + 64) i++ elseif c="Â" and ll_ascii < 192 then c=c2 i++ end if end if end choose new += c next return new
Puis-je y rajouter une ligne pour mon € ???
Merci
Dernière modification par Sylvie de hannut (04-03-2014 09:44:36)
Hors ligne
Sylvie de hannut a écrit:
Mais comment faire pour mettre dans une string mon document pbdom ????
Comme l'as dis Seki il suffit d'utiliser la méthode saveDocuementIntoString de pbdom_document
seki a écrit:
Petite question au passage, au vu du commentaire "Relire le xml (seule manière de l'avoir en string)", tu n'aurais pas simplement besoin de la méthode
Code: pb
pb_doc.SaveDocumentIntoString( )?
Cette méthode te retourne l'intégralité de ton pbdom_document en string.
Attention au nombre de caractère maximum du type string dépendant de ta version de PB (1073741823 caractère unicode en PB12 et 2147483647 caractères ascii en PB8 par exemple)
Hors ligne
Sylvie de hannut a écrit:
Ou alors que j'arrive à ouvrir le fichier en UTF-16.
As-tu essayé avec
FileOpen ( filename {, filemode {, fileaccess {, filelock {, writemode, { encoding }}}}} )
avec
encoding
Character encoding of the file you want to create. Specify this argument when you create a new text file using text or line mode.
If you do not specify an encoding, the file is created with ANSI encoding.
Values are:
- EncodingANSI! (default)
- EncodingUTF8!
- EncodingUTF16LE!
- EncodingUTF16BE!
Dernière modification par Geo (04-03-2014 10:08:49)
Hors ligne
Sylvie de hannut a écrit:
J'ai essayé, mais EncodingANSI! ne passe pas à la compilation
Tu es en PB9? Parce que ton code affreux de conversion utf8 -> ansi se fait en 2 lignes à partir de pb10 :
b = blob(s, encodingutf8!) s2 = string(b, encodingansi!)
Au fait pour la coloration du code pb sur pbadonf, et comme le rappelait erasorz, il faut écrire [ code = pb ] (sans les espaces)
pas PB ni Pb (c'est case-sensitive)
Hors ligne
Je n'ai pas cette fonction
Je suis en PB 9.0.3 build 8511
Puis-je rajouter cette fonction dans mon pbdom90.pbd ????
Hors ligne
Geo, en Pb 9, apparement il ne connait pas l'énuméré EncodingUTF16LE!
Le FileOpen ne passe pas la compile :-(
Hors ligne
J'ai retrouvé ce post qui peut pê te donner des pistes : http://pbadonf.fr/forum/viewtopic.php?id=3304
Je ne suis pas expert non plus en encoding mais je crois que le caractère € n'est correctement géré qu'en UTF16. Tu ne peux pas remplacer € par EUR dans les données qui servent de base lors du i_doc.SaveDocument() ?
Hors ligne
Merci Geo, je crois que c'est ce que je vais faire.
Je vais remplacer les symbôles par le texte ad hoc.
A moins que quelqu'un ici trouve une solution en PB9
J'ai bien un collègue qui a regardé pour migré l'application en PB12, mais on traîne trop de vieux chaudrons pour y arriver
Hors ligne
Le problème de ta fonction f_utf8_to_ansi() c'est qu'elle ne traite que quelques cas d'utf-8 et pas "€" comme tu l'avais remarqué.
En utf-8, les caractères < 128 sont codés sur 1 octet, et tous les autres sont codés entre 2 et 4 octets, alors que ta fonction ne traite que le cas où un caractère serait sur 1 ou 2 octets. Seulement "€" en utf-8 ça fait 3 octets (E2 82 AC, ou "€" représenté en "brut").
Plutôt que de coder un truc bancale pour effectuer la conversion, le plus simple est de demander à Windows de faire la conversion pour toi, il traitera tous les cas possibles et plus rapidement. Le code que je te propose convertit une chaîne en utf-8 (lu comme de l'ansi qui n'aurait pas été décodée) en wide-char avec MultiByteToWideChar() puis repasse en ANSI avec WideCharToMultiByte(). Le pivot avec un 3 encodage est nécessaire pour convertir correctement les caractères puisqu'en unicode (l'encodage qui est utilisé par le format utf-8) l'euro c'est U+20AC alors qu'en ansi c'est 80 (ou 128 en décimal)
En résumé, on fait E2 82 AC (utf-8) -> 20 AC (utf-16) -> 80 (ANSI). Le code a été fait en PB9
Tu as besoin de 2 protypes :
function ulong MultiByteToWideChar(ulong CodePage, ulong dwflags, ref string lpmultibytestr, ulong cchmultibyte, ref blob lpwidecharstr, ulong cchwidechar) library "kernel32.dll" function ulong WideCharToMultiByte(ulong CodePage, ulong dwFlags, ref blob lpWideCharStr, ulong cchWideChar, ref string lpMultiByteStr, ulong cbMultiByte, ref string lpUsedDefaultChar, ref boolean lpUsedDefaultChar) library "kernel32.dll"
la fonction de traduction qui remplace f_utf8_to_ansi(), valable jusque PB9. À partir de PB10 on peut convertir directement dans PB avec blob(), string(), encodingutf8! et encodingansi! :
public function string utf8_to_ansi (string as_utf8); //conversion utf-8 -> ansi //utilisation d'une chaîne native windows en wide-char comme pivot constant ulong CP_ACP = 0 constant ulong CP_UTF8 = 65001 string ls_wide, ls_ansi, ls_null blob lbl_wide ulong ul_len boolean lb_flag setnull(ls_null) lb_flag = false //on détermine la longueur de la chaine utf-8 convertie en wide-char //retourne un nombre de wide-chars setnull(lbl_wide) ul_len = multibytetowidechar(CP_UTF8, 0, as_utf8, -1, lbl_wide, 0) //on alloue la place pour que windows puisse écrire dedans, 1 wide-char = 2 octets ls_wide = space(ul_len * 2) lbl_wide = blob(ls_wide) //on passe par un blob car pb9 ne sait pas gérer des chaînes wide-char et s'arrête au 1er caractère //conversion utf-8 -> wide char ul_len = multibytetowidechar(CP_UTF8, 0, as_utf8, -1, lbl_wide, ul_len) //on détermine la longueur finale de la chaine ansi setnull(ls_ansi) ul_len = widechartomultibyte(CP_ACP, 0, lbl_wide, -1, ls_ansi, 0, ls_null, lb_flag) //on alloue la chaine pour que windows puisse écrire dedans ls_ansi = space(ul_len) //conversion wide-char -> ansi ul_len = widechartomultibyte(CP_ACP, 0, lbl_wide, -1, ls_ansi, ul_len, ls_null, lb_flag) return ls_ansi end function
test :
string ls_utf8 = "héhé : 1500€" messagebox("test", utf8_to_ansi(ls_utf8)) //--> héhé : 1500€
Dernière modification par seki (04-03-2014 12:29:09)
Hors ligne
Bravo Maître je m'incline et mon colègue aussi
Merci beaucoup
Hors ligne
Sylvie de hannut a écrit:
Bravo Maître je m'incline et mon colègue aussi
Merci beaucoup
bon maintenant que c'est réglé, c'est possible aussi de mettre les balise code=pb d'aplomb ?
Hors ligne
Seki,
j'ai déclaré les 2 fonctions comme des Global External function.
J'ai modifié la fonction globale avec ton code.
A l'exécution j'ai une erreur système n° 7:
unresolvable external multibytetowidechar when linking reference at line ... in function f_utf8_to_ansi
Qu'est ce que je n'ai pas fait correctement ?
Hors ligne
Complément d'information.
Après le plantage, j'ai fait un full build, puis j'airelancé ==> Boum
J'ai fermé PB + full build + go ==> boum
Vérification que les 2 fonctions se trouvent bien dans le kernell32 du répertoire c:\windows : oui elles y sont !!!
Redémarrage PC + full build + go ==> Boum Qu'est-ce qui n'est pas bon ?
Qu'est-ce que j'ai oublié ?????
Hors ligne
Sylvie de hannut a écrit:
Qu'est ce que je n'ai pas fait correctement ?
Mal copié / collé le code depuis le navigateur ?
Essaie ceci :
- fais planter ton PB avec le problème de "unresolved external"
- quand la messagebox avec l'erreur s'affiche, fais Control-C (ça doit te copier le contenu du message)
- viens ici coller le message *exact* de PB
On soupçonne un problème de casse... mais ici le message est "Error: Error calling external function..." pas "unresolved external"
Hors ligne