L'obtention de std :: ifstream pour gérer LF, CR, et CRLF?
Spécifiquement, je m'intéresse à istream& getline ( istream& is, string& str );
. Est-il une option pour le ifstream constructeur pour lui demander de convertir tous les newline codages de '\n' sous le capot? Je veux être en mesure d'appeler getline
et ont gracieusement gérer toutes les fins de ligne.
Mise à jour: Pour clarifier, je veux être capable d'écrire du code qui compile presque n'importe où, et va prendre une entrée à partir de presque n'importe où. Y compris les rares fichiers qui ont '\r' sans '\n'. En minimisant les inconvénients pour les utilisateurs du logiciel.
Il est facile de contourner le problème, mais je suis toujours curieux de connaître le droit chemin, dans la norme, pour la souplesse gérer tous les formats de fichier texte.
getline
lit une ligne entière, jusqu'à un '\n', dans une chaîne de caractères. Le '\n' est consommé à partir du flux, mais getline ne pas l'inclure dans la chaîne. C'est très bien jusqu'à présent, mais il pourrait y avoir un '\r' juste avant le '\n' qui est inclus dans la chaîne.
Il y a trois types de fins de ligne vu dans les fichiers de texte:
'\n') est le classique se terminant sur des machines Unix, '\r' était (je pense) utilisé sur les anciens systèmes d'exploitation Mac et Windows utilise une paire, '\r' suivi par '\n'.
Le problème est que getline
quitte le '\r' sur la fin de la chaîne.
ifstream f("a_text_file_of_unknown_origin");
string line;
getline(f, line);
if(!f.fail()) { //a non-empty line was read
//BUT, there might be an '\r' at the end now.
}
Modifier Merci à Neil pour préciser que f.good()
n'est pas ce que je voulais. !f.fail()
est ce que je veux.
Je peux le supprimer manuellement moi-même (voir l'édition de cette question), ce qui est facile pour les Windows fichiers texte. Mais je suis inquiet que quelqu'un, un aliment dans un fichier ne contenant que des '\r'. Dans ce cas, je présume que getline consomme l'ensemble du fichier, en pensant que c'est une seule ligne!
.. et c'est même pas envisagé Unicode 🙂
.. peut-être Boost est une belle façon de consommer, ligne par ligne à partir de n'importe quel texte-type de fichier?
Modifier je suis en utilisant ce, pour gérer les fichiers de Windows, mais j'ai toujours l'impression que je ne devrais pas! Et ce ne sera pas la fourche pour le '\r'-seuls les fichiers.
if(!line.empty() && *line.rbegin() == '\r') {
line.erase( line.length()-1, 1);
}
même si je suis de compiler sur une machine Linux, parfois, je suis en utilisant des fichiers texte qui sont venus à l'origine à partir d'une machine Windows. Je pourrais sortir mon logiciel (un petit outil pour l'analyse de réseau), et je veux être en mesure d'indiquer aux utilisateurs qu'ils peuvent se nourrir dans presque n'importe quel moment de l' (ASCII) fichier texte.
Peu de cas de test qui démontre votre question.
Notez que si(f.bonne()) ne fait pas ce que vous semblez penser qu'il fait.
Il peut avoir été comme ceci. Peut-être.
OriginalL'auteur Aaron McDaid | 2011-05-22
Vous devez vous connecter pour publier un commentaire.
Que Neil a souligné, "le C++ runtime doit traiter correctement avec la ligne de fin de la convention est à votre plate-forme."
Cependant, les gens ne déplacer des fichiers texte entre les différentes plates-formes, donc qui n'est pas assez bon. Voici une fonction qui gère tous les trois fins de ligne ("\r", "\n" et "\r\n"):
Et ici est un programme de test:
Weller: le constructeur et Le destructeur de la sentinelle sont exécutées. Ces faire des choses comme la synchronisation de thread, de sauter des blancs de l'espace et de la mise à jour de l'état de flux.
Dans les expressions du FOLKLORE cas, quel est le but de vérifier que l'
t
est vide avant de le eofbit. Ne pourrait-il pas peu être défini indépendamment des autres personnages ayant été lu?Yay295: Les expressions du folklore indicateur doit être défini, pas lorsque vous atteignez la fin de la dernière ligne, mais lorsque vous essayez de lire au-delà de la dernière ligne. La vérification permet de s'assurer que ce qui se passe quand la dernière ligne n'a pas de fin de ligne (EOL. (Essayez de supprimer le vérifier, puis exécutez le programme de test sur un fichier texte où la dernière ligne n'a pas de fin de vie, et vous verrez.)
"...mais lorsque vous essayez de lire au-delà de la dernière ligne." N'est-ce pas pourquoi
c == EOF
? Parce que nous lire au-delà de la dernière ligne? Je l'ai essayé, sans que l'enregistrement et il a fonctionné correctement. Avec cette case imprimer un interligne supplémentaire qui n'existe pas dans le fichier d'origine.OriginalL'auteur
Le C++ runtime doit traiter correctement avec la finale de la convention est à votre plate-forme. Plus précisément, ce code devrait fonctionner sur toutes les plateformes:
Bien sûr, si vous travaillez avec des fichiers à partir d'une autre plate-forme, tous les paris sont éteints.
Comme les deux principales plates-formes (Linux et Windows) à la fois mettre fin à des lignes avec un caractère de saut de ligne, avec Windows précédents, avec un retour chariot, vous pouvez examiner le dernier caractère de la
line
chaîne de caractères dans le code ci-dessus pour voir si c'est\r
et si donc l'enlever avant de faire votre traitement spécifique à l'application.Par exemple, vous pouvez fournir vous-même avec un getline style de fonction qui ressemble à quelque chose comme ça (pas testé, l'utilisation de l'index, substr, etc à des fins pédagogiques uniquement):
cette réponse n'est pas suffisant encore. Si je justed voulaient traiter CRLFs, je ne serais pas venu à StackOverflow. Le véritable défi est de gérer les fichiers uniquement '\r'. Ils sont assez rares de nos jours, maintenant que MacOS a déménagé pour se rapprocher de Unix, mais je ne veux pas supposer qu'ils ne seront jamais être nourris à mon logiciel.
eh bien, si vous voulez être en mesure de gérer TOUT ce que vous devez écrire votre propre code pour le faire.
Je l'ai précisé dans ma question depuis le début qu'il est facile de contourner ce problème, ce qui implique que je suis prêt et en mesure de le faire. J'ai demandé à ce sujet car il semble être une question commune, et il ya une variété de texte-les formats de fichier. Je suppose/espéré que le C++ comité de normalisation avait construit ce dans. C'était ma question.
Je pense qu'il y a un autre problème que j'ai/nous avons oublié. Mais d'abord, je reconnais que c'est pratique pour moi d'identifier un petit nombre de formats pris en charge. Donc, je veux le code qui permettra de compiler pour Windows et Linux et qui va travailler avec l'un ou l'autre format. Votre
safegetline
est une partie importante de la solution. Mais si ce programme est compilé sur Windows, vais-je besoin pour ouvrir un fichier au format binaire? Ne compilateurs pour Windows (en mode texte) permettent de '\n' à se comporter comme un '\r\n'?ifstream f("f.txt", ios_base :: binary | ios_base::in );
OriginalL'auteur Neil Butterworth
Êtes-vous de lire le fichier dans BINAIRE ou dans TEXTE mode? Dans TEXTE mode, la paire de retour chariot/saut de ligne, CRLF, est interprété comme TEXTE la fin de la ligne, ou le caractère de fin de ligne, mais dans BINAIRE vous récupérer uniquement UN octet à la fois, ce qui signifie que l'un des personnages DOIT être ignoré et laissé dans la mémoire tampon pour être extraites comme un autre octet! Retour chariot signifie, dans la machine à écrire, que la machine à écrire de voiture, d'où l'impression bras réside dans, a atteint le bord droit du papier et est renvoyé vers le bord gauche. C'est un très mécanique modèle, celui de la machine à écrire mécanique. Puis le saut de ligne signifie que le rouleau de papier est tourné un peu pour que le papier est en position de commencer une nouvelle ligne de saisie. Comme fas comme je me souviens de l'un de la faible chiffres ASCII signifie se déplacer vers la droite d'un caractère sans avoir à taper, le char morts, et bien sûr, \b signifie backspace: déplacer la voiture un caractère de retour. De cette façon, vous pouvez ajouter des effets spéciaux, comme des sous-jacent (type de trait de soulignement), barré (type moins), approximative des accents différents, annule (type X), sans avoir besoin d'un clavier étendu, simplement en ajustant la position de la voiture le long de la ligne avant d'entrer dans la ligne d'alimentation. Ainsi, vous pouvez utiliser octets de taille ASCII tensions de contrôler automatiquement une machine à écrire sans un ordinateur entre les deux. Lorsque la détection automatique d'une machine à écrire est introduit, AUTOMATIQUE signifie qu'une fois que vous atteignez le plus éloigné bord de la feuille, la voiture est retournée à la gauche de la ET le saut de ligne appliquée, qui est, la voiture est supposé être retourné automatiquement à mesure que le rouleau se déplace vers le haut! Donc, vous n'avez pas besoin à la fois des caractères de contrôle, un seul, le \n, nouvelle ligne, ou un saut de ligne.
Cela n'a rien à voir avec la programmation, mais ASCII est plus âgé et HEY! regarde comme certaines personnes n'ont pas été pensée quand ils ont commencé à faire du texte de choses! La plate-forme UNIX suppose électrique automatique typemachine; le modèle de Windows est plus complet et permet le contrôle de la mécanique des machines, même si certains caractères de contrôle deviennent de moins en moins utile dans les ordinateurs, comme la cloche de caractère, 0x07 si je me souviens bien... Certains textes oubliés doit avoir été à l'origine capturé avec des caractères de contrôle pour la commande électrique des machines à écrire et elle a perpétué le modèle...
Fait le bon variation serait simplement d'inclure les \r, saut de ligne, retour chariot inutile, c'est automatique, donc:
serait la plus correcte pour gérer tous les types de fichiers. Notez cependant que les \n dans TEXTE mode est en fait l'octet paire 0x0d 0x0a, mais 0x0d EST \r: \n comprend \r dans TEXTE mode mais pas dans BINAIRE, ainsi \n et \r\n sont équivalentes... ou devrait l'être. C'est un très de base de l'industrie de la confusion en fait, typique de l'inertie de l'industrie, comme la convention est de parler de CRLF, dans TOUTES les plates-formes, tombent ensuite dans différents binaires interprétations. Strictement parlant, les fichiers, y compris SEULEMENT 0x0d (retour chariot) \n (CRLF ou saut de ligne), sont mal formés dans TEXTE mode (typewritter de la machine: il suffit de retourner la voiture et barré tout...), et sont un non-ligne orientée format binaire (soit \r ou \r\n sens de la ligne), de sorte que vous ne sont pas censés lire que du texte! Le code devrait échouer peut-être avec quelques message de l'utilisateur. Cela ne dépend pas de l'OS, mais aussi sur la bibliothèque C de mise en œuvre, ajoutant à la confusion et les variations possibles... (en particulier pour la transparence de traduction UNICODE couches d'ajouter un autre point d'articulation dans la confusion entre les variations).
Le problème avec l'extrait de code précédent (machine à écrire mécanique), c'est qu'il est très inefficace si il n'y a aucun \n caractères à la suite de \r (automatique machine à écrire du texte). Puis il suppose également BINAIRE mode où la bibliothèque C est contraint d'ignorer texte interprétations (paramètres régionaux) et donner la pure octets. Il devrait y avoir aucune différence dans le texte tous les caractères entre les deux modes, que dans le contrôle des personnages, donc en général la lecture BINAIRE est mieux que TEXTE mode. Cette solution est efficace pour BINAIRE mode typique de système d'exploitation Windows fichiers texte, indépendamment des variations de la bibliothèque C, et inefficace pour les autres plate-forme de formats de texte (y compris les traductions dans le texte). Si vous vous souciez de l'efficacité, de la manière de faire est d'utiliser un pointeur de fonction, faire un test pour \r vs \r\n des contrôles en ligne cependant manière dont vous le souhaitez, puis sélectionnez le meilleur getline utilisateur-code dans le pointeur et l'invoquer.
D'ailleurs je me souviens que j'ai trouvé un \r\r\n fichiers texte trop... ce qui se traduit par une double ligne de texte, tout comme l'est toujours exigé par certains textes imprimés aux consommateurs.
OriginalL'auteur Danilo J. Bonsignore
Autres que la rédaction de votre propre gestionnaire ou à l'aide d'une bibliothèque externe, vous êtes hors de la chance. La meilleure chose à faire est de vérifier
line[line.length() - 1]
n'est pas '\r'. Sur Linux, c'est superflu, comme la plupart des lignes jusqu'à la fin avec '\n', ce qui signifie que vous allez perdre un peu juste de temps si c'est dans une boucle. Sur Windows, c'est aussi superflu. Cependant, ce sur classique Mac fichiers qui se terminent par '\r'? std::getline ne serait pas travailler pour ces fichiers sur Linux ou sur Windows parce que '\n' et '\r' '\n' à la fois la fin avec des '\n', éliminant ainsi la nécessité de vérifier le '\r'. Évidemment, une telle tâche qui fonctionne avec les fichiers ne fonctionnerait pas bien. Bien sûr, il existe de nombreux EBCDIC systèmes, quelque chose que la plupart des bibliothèques n'oseront pas s'attaquer.Vérifier '\r' est probablement la meilleure solution à votre problème. La lecture en mode binaire vous permettrait de vérifier pour tous les trois communes les fins de ligne ('\r', '\r\n' et '\n'). Si vous ne se soucient que Linux et Windows en tant qu'ancien de style Mac fins de ligne ne devrait pas être autour pendant beaucoup plus longtemps, '\n' et supprimer le caractère nul '\r' caractère.
OriginalL'auteur
Une solution serait de d'abord rechercher et remplacer toutes les fins de ligne '\n' - comme par exemple Git le fait par défaut.
OriginalL'auteur user2061057