7
votes

Comportement Qtextstream Recherche d'une chaîne non comme prévu

J'ai ces quelques lignes de code:

this is line one, the first line
this is line two, it is second
this is the third line
and this is line 4
line 5 goes here
and finally, there is line number 6


10 commentaires

Je devinerais quelque chose à voir avec les fins de ligne, êtes-vous sur une plate-forme de fenêtre? Si oui, vos terminaisons de ligne peuvent être deux octets chacun.


@John - Non, je reçois des résultats attendus pour les lignes précédentes et chaque ligne a un \ n - je devrais avoir un problème pour chaque ligne. Si j'adore la compensation à 2, je reçois un mauvais résultat pour les lignes précédentes.


Peut-être que vous avez un fichier avec des terminaisons de ligne mixtes? En tout cas, votre approche est intrinsèquement risquée. Je ne connais pas le Qtextstream mais dans la norme équivalente C ++, votre code n'aurait pas de comportement bien défini. Je voudrais simplement lire le fichier entier dans une chaîne et le manipuler à partir de là.


@John - C'est ce que je fais généralement, mais l'exigence ici est que le fichier pourrait être assez gros et non tout à fait nécessaire, c'est pourquoi je souhaite trouver la chaîne "Termination" et charger uniquement du début.


BTW I a également vérifié, la taille du fichier réelle confirme que la fin de la ligne est un octet unique.


Si le cas d'utilisation habituel est que la chaîne est trouvée dans le fichier ou si les fichiers ne sont pas énormes, il peut être préférable de stocker les lignes que vous avez déjà lues au lieu de les lire à nouveau.


@Roku - Oui, mais il est nécessaire de minimiser les opérations de concaténation. Et en plus, lire à nouveau que le fichier ne contient aucune dépense, au moins sous Windows, car le fichier est déjà mis en cache en mémoire.


Vous pouvez stocker les lignes à qlist, puis les imprimer sans aucune concaténation.


@Roku - J'ai fait cela avec une QStringlist, mais j'aimerais toujours enquêter sur cette affaire.


S'il vous plaît, revoyez ma réponse: Stackoverflow.com/a/16100974/1035613


5 Réponses :


2
votes

Je ne suis pas tout à fait sûr de savoir pourquoi vous voyez ce comportement, mais je soupçonnerais que ce soit lié aux fins de la ligne. J'ai essayé votre code et j'ai seulement vu le comportement la dernière ligne lorsque le fichier avait des terminaisons de ligne CRLF et il n'y avait pas de nouvelle ligne (CRLF) à la fin du fichier. Alors oui, bizarre. Si le fichier avait des terminaisons de ligne LF, il a toujours fonctionné comme prévu.

avec cela dit, ce n'est probablement pas une bonne idée de garder une trace de la position en ajoutant + 1 à la fin de chaque ligne Parce que vous ne saurez pas si votre fichier source était CRLF ou LF et QTEXTStream dépouilleront toujours les fins de la ligne. Voici une fonction qui devrait fonctionner mieux. Il construit la ligne de chaîne de sortie par ligne et je n'ai vu aucun comportement étrange avec celui-ci: xxx

Il ne reste pas une trace de la position dans le flux d'origine, Donc, si vous vouliez vraiment une position, je vous recommande d'utiliser Qtextstream :: POS () car il sera précis si le fichier est CRLF ou LF.


1 commentaires

Votre solution n'échappe pas à un gros dossier, disons avec des lignes de looong



2
votes

Le Qtextstream.read () La méthode prend en tant que Paramètre Le nombre maximum de caractères à lire, pas une position de fichier. Dans de nombreux environnements, la position n'est pas un bloc de caractères simples: VMS et Windows se viennent à l'esprit comme des exceptions. VMS impose une structure d'enregistrement qui utilise de nombreux bits cachés de métadonnées dans les positions de fichiers et de fichiers sont "cookies magiques"

Le seul moyen indépendant de système de fichiers pour obtenir la bonne valeur est d'utiliser qtextstream :: POS () Lorsque le fichier est déjà positionné au bon endroit, puis continuez à lire jusqu'à ce que la lecture La position du fichier retourne au même emplacement.

(expurgé parce qu'il y avait une exigence initialement non spécifiée interdisant à plusieurs allocations de tamponner le texte.)
Toutefois, compte tenu des exigences du programme, il n'a aucun sens de relire la première partie du fichier. Commencez à sauvegarder le texte au début et à l'arrêt lorsque la chaîne est trouvée: xxx

puisque vous êtes sous Windows, le traitement du fichier texte est Traduire '\ r \ n' en '\ n' et qui provoque une inadéquation dans le positionnement du fichier contre le comptage de caractères. Il y a plusieurs façons de contourner cela, mais peut-être que le plus simple est simplement de traiter le fichier comme binaire (c'est-à-dire non pas "texte" en laissant tomber le mode texte ) pour empêcher la traduction: xxx

puis le code doit fonctionner comme prévu. Il ne fait aucun dommage à la sortie \ R \ N sous Windows, mais peut parfois causer des affichages de nuisance lors de l'utilisation des utilitaires de texte Windows. Si cela est important, recherchez et remplacez \ r \ n avec \ n une fois que le texte est en mémoire.


5 commentaires

L'exigence était d'éviter la réaffectation. Ces opérations de concaténation peuvent devenir de plus en plus lourdes pour les grands fichiers d'entrée. Stocker et résumer toutes les lignes à la fois ne sont pas souhaités non plus.


@DDRiver: Pouvez-vous être assuré que le programme ne sera pas tenu de fonctionner sur un système de fichiers opaque? C'est-à-dire qu'il ne fonctionnera-t-il que sur Linux, Unix, etc.?


La question de différents formats de représentant du texte sur différentes plateformes est reconnue. Ce n'est pas la question de la question. Mon entrée de texte est exactement le nombre de caractères + 1 octet pour chaque EOL. Je veux savoir pourquoi je reçois le comportement attendu lors de la recherche sur toutes les lignes, à l'exception de la dernière.


@DDRiver: Quelle plate-forme fonctionne-t-elle?


@DDRiver: J'ai modifié ma réponse en conséquence.



4
votes

Évidemment, vous obtenez ce comportement car readline () saute le curseur par taille de ligne avec des caractères de délimitation de ligne (SLF CRLF ou CR en fonction du fichier). tampon que vous obtenez de cette méthode ne conteste pas ces symboles , vous ne prenez donc pas ces caractères dans vos calculs de position.

La solution consiste à lire non par des lignes mais par tampon. Voici votre code, modifié: xxx

edit

Le code ci-dessus contient une erreur due à la mémoire tampon. . Voici une entrée d'échantillon qui brise des trucs (en supposant que nous sausions de la peau): xxx

solution

ici est Code complet Ce qui fonctionne bien avec toutes les entrées que j'ai essayées: xxx


0 commentaires

4
votes

Lorsque vous recherchez sur la dernière ligne, vous lisez tout le flux d'entrée - in.Atend () retourne vrai. On dirait que cela corrompt en quelque sorte le fichier de fichiers ou de texte, ou les définit hors de la synchronisation, alors recherchez n'est plus valide.

Si vous remplacez xxx

par xxx

Cela fonctionnera comme prévu. P.s. Il peut s'agir d'une solution plus propre puis de ré-ouvrir le fichier, mais le problème provient définitivement d'atteindre la fin des flux et du fichier et d'essayer de les utiliser après ...


0 commentaires

3
votes

Vous connaissez la différence entre Windows et * Nix fins de ligne (\ r \ n vs \ n). Lorsque vous ouvrez le fichier en mode texte, vous devez savoir que toute la séquence de \ r \ n est transtalée à \ n.

Votre erreur dans le code d'origine que vous essayez de calculer le décalage de la ligne sautée, mais vous ne le savez pas Longueur exacte de la ligne dans le fichier texte. xxx

Vous ne pouvez pas détecter number_of_eol_chars sans accès brut au fichier. Et vous ne l'utilisez pas dans votre code, car vous ouvrez le fichier comme texte, mais pas aussi binaire. Donc, Erreur dans votre code, que vous aviez codé en papier number_of_eol_chars avec 1, au lieu de la détecter. Pour chaque ligne dans les fichiers texte Windows (avec \ r \ n eol), vous obtiendrez une erreur dans POS pour chaque ligne sautée.

code fixe: xxx


2 commentaires

"Pour chaque ligne dans les fichiers texte Windows (avec \ r \ n eol), vous serez une erreur dans POS pour chaque ligne sautée" - mais je ne reçois pas une erreur en position pour chaque ligne sautée, je n'ai que la mauvaise position lorsque Le texte recherché est sur la dernière ligne, sinon il est bon.


Strange ... Pourriez-vous fournir votre exemple d'origine (source + fichier texte, en tant que .zip)? Parce que le code que vous avez posté fonctionne comme prévu pour moi (comme je l'ai décrit dans mon poste - chaque ligne donne -1 erreur de position), si le fichier texte utilise \ r \ n eol.