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

C++/CLI Discussion :

Lecture de fichier ASCII / UNICODE. DEBUTANT


Sujet :

C++/CLI

  1. #1
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut Lecture de fichier ASCII / UNICODE. DEBUTANT
    Bonjour à tous,
    C'est la première fois que je viens poster sur ce forum. Je débute en c++, même si j'ai longtemps 'bricoler' en C. Je bloque aujourd'hui sur un problème extrêmement bête que je ne comprend pas.
    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
    #include <string>  
    #include <fstream>
    using namespace std;
    int main()
    {
    	string line;
    	fstream text("monfichier.txt");
    	while (getline(text,line))
    	{
    		cout << line << endl;	
    	}
    return 0;
    }
    Il n'y a, pour la plupart des fichiers que je traite, aucun problème, par contre j'ai pu identifier, sur des fichiers registre (*.reg) un problème lors de la sortie de ma chaine.
    En effet, celle ci contient des espaces entre chaque caractère, c'est très pénible à traiter.
    Quand j'affiche la variable çà écrit par exemple ce genre de chose :
    [ H K E Y _ C U R R E N T _ C O N F I G \ \ S y s t e m \ C u r r e n t C o n t r o l S e t \ C o n t r o l \ V I D E O ]
    alors que mon fichier d'origine contient bien :
    [HKEY_CURRENT_CONFIG\\System\CurrentControlSet\Control\VIDEO]
    Et du coup impossible de , par exemple, réinjecter les chaine obtenu dans un nouveau fichier.
    J'ai testé avec des .reg fabriqué manuellement il n'y a aucun probléme.
    Les fichiers qui présente des problèmes sont fabriqué à partir de la commande regedit /e.
    Ce que je ne comprend absolument pas c'est pourquoi cette différence de résultat alors que les fichiers sont traités de la même manière?
    J'ai clairement loupé un truc essentiel mais quoi?
    Si quelqu'un veux bien m'éclairer?
    Merci d'avance

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ce ne sont pas des espaces, mais des octets nuls, je parie. Problème d'encodage, entre UTF-16 et les ASCIIs étendus.

    Je ne connais pas assez la bibliothèque standard du C++ natif (surtout avec les normes récentes) pour savoir s'il y a quelque chose pour gérer ça directement.
    Mon conseil: Puisque tu as posté dans le sous-forum consacré au langage C++/CLI pour le Framework .net, utilise le framework .Net pour de bon, car lui est fait pour ça (un System::IO::StreamReader permet de spécifier l'encodage des fichiers).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 074
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    C'est la première fois que je viens poster sur ce forum
    Et vraisemblablement la dernière dans cette partie du forum.
    Ne le prend pas mal, c'est juste que cette partie du forum est lié à "C++/CLI", une version étendue par M$ du C++.
    Il y a donc beaucoup moins de "flux" ici que dans les parties du forum plus généraliste.
    https://www.developpez.net/forums/f1...p/cpp/debuter/

    T'es loin d'être le premier et tu ne seras pas le dernier à faire cette petite erreur.

    J'ai clairement loupé un truc essentiel mais quoi?
    Le fait que distinguer des fichiers en ASCII et en UNICODE, c'est la mer.. .

    Votre code ne fonctionne qu'avec des fichiers textes en ASCII (étendu 8bits).
    Le fichier "*.reg" que vous lisez n'est pas en ASCII, mais en UNICODE-16 (sans BOM (Byte Order Mark)).
    Pour des caractères contenus dans la table des ASCII 7bits, la version UNICODE-16 de ce caractère est composé d'un octet à '\0' suivi du même octet que son encodage en ASCII.
    'H' en ASCII : 72 (ou 0x48)
    'H' en UNICODE-16 (en little endian): 00-72 (ou 0x0048)

    La console que vous utilisez doit afficher un '\0' sous forme d'un espace.

    La mer.., c'est que rien n'indique l'encodage d'un fichier.
    Je crois que l'encodage officiel des .reg est UNICODE-16 (ou UTF-8 ?).
    Il est possible que les interpréteurs de ".reg" utilisent des heuristiques pour détecter un mauvais encodage pour encaisser des fichiers "mals" encodés.

    C'est quoi votre objectif ?

    Pour lire directement de UTF-16/UNICODE-16 :
    http://www.cplusplus.com/reference/fstream/wfstream/

  4. #4
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut
    Bonjour et merci pour vos réponses rapides.
    En effet, je suis pas du tout dans la bonne partie du forum et j'en suis désolé (je découvre ) ).
    Si un modérateur veux bien déplacer le sujet je le remercie d'avance.
    Effectivement quand j’écris ma chaine dans un fichier et que je visionne celui-ci je n'ai pas d'espace mais des petit logos 'NULL'.
    Donc clairement un problème ASCII vs UNICODE. J'avoue que je n'avais jamais eu ce problème en C donc j’étais un peu perplexe.
    Je cherche une solution de ce coté la et je viens poster la solution ici, au cas ou quelqu'un rencontre le même problème.
    Mon objectif est de pouvoir extraire les données registre avant et après l'installation , par exemple, d'un programme, afin de pouvoir 'fabriquer' un point reg permettant de 'bricoler' un déploiement réseau pour les rares logiciels qui ne le permettent pas par défaut. Également pour différencier ou se trouve certaine information dans le registre avant et après modification de certaines configurations etc...
    Bref, c'est un problème auquel je suis parfois confronté et je me bricole mon outil maison.
    Merci de votre regard extérieur qui m'a permis d'avancer , un peu plus, dans cette direction.

  5. #5
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut
    A première vue je suis loin d’être le seul à avoir eu ce genre de soucis.
    Je pense qu'il y a une solution viable de ce coté la
    https://msdn.microsoft.com/fr-fr/lib...code-snippet-2
    (Je poste aussi ce lient pour mémoire à moi même).
    Par contre j'ai énormément de mal avec la syntaxe et je n'y connais rien dans l'implémentation (arrêtè moi si le mot n'est pas bon) des framework en c++.
    J'ai copié/collé le code en exemple tel quel sans aucun autre résultat qu'une longue série d'erreur.
    Je continu de chercher/fouillé et je viendrais de toutes façons posté ma réponse ici.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 074
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    J'avoue que je n'avais jamais eu ce problème en C donc j’étais un peu perplexe.
    Le problème n'a rien à voir avec le langage.
    Vous aurez le même problème en C qu'en C++.

    Je pense que vous n'aviez pas conscience du problème car UNICODE c'est répandu qu'à la fin des années 1990 dans les systèmes "desktop" et je pense qu'il a pris du temps pour arriver dans les systèmes embarqués.
    Donc si vous faisiez du C dans un périmètre (temporel / plateforme) où l'UNICODE n'était pas répandu, vous n'étiez pas tombé dessus, mais c'est pas "grâce" au C.

    Je ne comprend pas trop pourquoi la version "wide" des manipulations de stream dont j'ai posté le lien (http://www.cplusplus.com/reference/fstream/wfstream/) n'est pas une solution viable ?

    Avec cette version, vous ne manipulez que de l'UNICODE, donc vous êtes d'équerre avec le format des ".reg" en UTF-16.

    Vos besoins sont assez classique, me semble-t-il, c'est pourquoi j'ai l'impression qu'il serait peut-être possible de faire ces choses juste avec des outils pré-existant, non ?
    Peut-être avec des fichiers ".bat" de quelques lignes ?

    Je pense qu'il y a une solution viable de ce coté la
    Ce que vous regardez, ce n'est pas du C++ "standard", c'est du code en "C++/CLI" (oui, celui de ce forum ).
    Pour pouvoir se servir de ces trucs, il faut être dans un contexte d'exécution .NET.
    Là, je pense que c'est un peu overkill et un peu dangereux pour une personne sans un background en C++ ou dans un langage .NET.
    En plus, avec ces API, il faut aussi spécifier l'encodage du fichier que l'on cherche à lire.

    Donc, à moins d'avoir oublier un détail, je pense que l'approche "wfstream" sera bien plus simple.

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    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 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par bacelar Voir le message
    La mer.., c'est que rien n'indique l'encodage d'un fichier.
    Si le BOM (Byte order mark)

    Ensuite si tu parses un fichier .html, il y a les méta-données.


    Citation Envoyé par neokal Voir le message
    Donc clairement un problème ASCII vs UNICODE.
    Pas vraiment, puisque en C, il y a char[*] VS wchar_t

    *: signé ou pas, quoique pour l'UTF8 j'utilise du non signé

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je ne comprend pas trop pourquoi la version "wide" des manipulations de stream dont j'ai posté le lien (http://www.cplusplus.com/reference/fstream/wfstream/) n'est pas une solution viable ?
    La dernière fois que j'avais essayé un truc de ce genre, il m'a ouvert le fichier en tant qu'ASCII et faisait la conversion (voire un bête cast, je ne suis pas sûr) en wchar_t à la volée...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut Convertir un fichier de UTF-16 vers UTF-8 avec la STL, en passant par UTF-32.
    Au cas où mon code soit utile à quelqu'un, voici un programme qui lit un fichier encodé en UTF-16 et le convertit en UTF-8 :
    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
    #include <codecvt>
    #include <fstream>
    #include <iostream>
    #include <locale>
     
    int main(int argc, char** argv)
    {
    	try {
     
    		if(argc < 2) {
    			throw std::runtime_error("Pas assez d'arguments. Il en faut deux :"
    				" l'adresse d'un fichier en entree encode en UTF-16"
    				" et l'adresse d'un fichier en sortie qui sera encode en UTF-8.");
    		}
     
    		const char* const cheminFichierEntreeUTF16 = argv[1];
    		const char* const cheminFichierSortieUTF8  = argv[2];
     
    		std::basic_ifstream<char32_t> fic_entree_utf16(cheminFichierEntreeUTF16, std::ios::binary);
    		if(!fic_entree_utf16)
    			throw std::runtime_error("Impossible d'ouvrir le fichier en entree.");
    		fic_entree_utf16.imbue(std::locale(
    			fic_entree_utf16.getloc(),
    			new std::codecvt_utf16<char32_t, 0x10ffff, std::consume_header>
    		));
     
    		std::basic_ofstream<char32_t> fic_sortie_utf8(cheminFichierSortieUTF8, std::ios::binary);
    		if(!fic_sortie_utf8)
    			throw std::runtime_error("Probleme avec le fichier en sortie.");
    		fic_sortie_utf8.imbue(std::locale(
    			fic_sortie_utf8.getloc(),
    			new std::codecvt_utf8<char32_t, 0x10ffff, std::generate_header>
    		));
     
    		char32_t carac_utf32;
    		while(fic_entree_utf16.good())
    		{
    			fic_entree_utf16.get(carac_utf32);
    			if(fic_entree_utf16.fail() == false)
    			{
    				fic_sortie_utf8 << carac_utf32;
    				if(fic_sortie_utf8.fail())
    					throw std::runtime_error("Probleme lors de l'ecriture du fichier en sortie.");
    			}
    		}
     
    	} catch(const std::exception& e) {
    		std::cerr << e.what();
    		return 1;
    	} catch(...) {
    		std::cerr << "Erreur inconnue.";
    		return 2;
    	}
     
    	return 0;
    }
    Remarques :
    • S'il n'y a pas de caractère BOM dans le fichier en entrée, il faut remplacer std::consume_header par (std::codecvt_mode)0 (qui est déjà l'argument de template par défaut) ou std::little_endian.
    • Si on ne veut pas de caractere BOM dans le fichier en sortie, il faut remplacer std::generate_header par (std::codecvt_mode)0.

  10. #10
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    La dernière fois que j'avais essayé un truc de ce genre, il m'a ouvert le fichier en tant qu'ASCII et faisait la conversion (voire un bête cast, je ne suis pas sûr) en wchar_t à la volée...
    C'est normal. En fait, il faut distinguer la suite d'octets du fichier et la suite de caractères de type CharT stockée dans le buffer de type std::basic_filebuf<CharT, Traits> encapsulé par std::basic_ifstream<CharT, Traits> et std::basic_ofstream<CharT, Traits>.
    Dans le cas où CharT n'est pas char (par exemple char32_t dans le code de mon précédent message), il y a une conversion avec un std::codecvt. Pour maîtriser la conversion, il faut alors changer la locale utilisée par le flux.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ah merci, je me disais bien (avec le recul; ma tentative d'utiliser wifstream remonte à des années) que les locales seraient impliquées, mais je ne me souvenais plus du tout comment.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut
    J'ai utilisé cette petite fonction, elle permet d'avoir en retour une chaine string au format utf8 de la chaine string utf16 passé en argument,
    C'est juste une fonction qui fait sauter un caractère sur deux , pas forcément super élégant mais ça m'a bien dépanné.

    Merci en tout cas pour l'aide apportée.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    string utf16_to_utf8(string into)    {
    	string outo;
    	int i=0;
    	bool pendulum = 0;
    	for(i=0;i<into.size();i++)
    	{
    		if (pendulum==1)	
    			outo+=into[i];
    		if (pendulum == 0) pendulum=1;
    			else pendulum = 0;
    	}
    	return outo;
    }	//END utf16utf8

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Le nom de ta fonction est archi-faux: Même en supposant que le "un octet sur deux" est systématiquement nul, le résultat n'est pas de l'UTF-8, mais de l'ISO 8859-1.

    Si tu veux faire de la vraie conversion en UTF-8 sans appeler de fonctions non-standard et sans avoir à comprendre comment marchent les locales, il te faudra une fonction de ce genre:
    https://www.developpez.net/forums/d1...e/#post8502203
    (note que la fonction de conversion prend un code point en entrée; cela veut dire que lui passer directement les paires d'octets lus est approprié pour convertir depuis l'UCS-2; pour convertir depuis du vrai UTF-16, il faut un peu plus de travail).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

Discussions similaires

  1. problème lors de la lecture d'un fichier
    Par salseropom dans le forum C++
    Réponses: 16
    Dernier message: 29/09/2011, 15h10
  2. Problème lors de la lecture d'un fichier
    Par _SamSoft_ dans le forum C
    Réponses: 2
    Dernier message: 23/02/2008, 15h14
  3. Problème lors de la lecture d'un fichier xml avec XMLBeans
    Par oscar78 dans le forum Format d'échange (XML, JSON...)
    Réponses: 1
    Dernier message: 07/09/2007, 14h04
  4. Problèmes lors de la lecture d'un fichier
    Par samothtronicien dans le forum C++
    Réponses: 5
    Dernier message: 27/05/2006, 00h05
  5. Problème lors de la lecture d'un fichier avec Input...
    Par Kronoob dans le forum VB 6 et antérieur
    Réponses: 13
    Dernier message: 18/11/2005, 18h55

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