Code ne prends pas en compte toutes les lignes

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Code ne prends pas en compte toutes les lignes

Re: Code ne prends pas en compte toutes les lignes

par carte-sd » 02 juin 2016, 13:44

@Ryle
C'est vraiment subtile, je viens de réaliser quelques tests et effectivement, j'ai compris, ça risque de me prendre un certain temps avant d'intégrer tout ça dans ma tête, c'est déroutant.
Je vais de ce pas me renseigner sur or / and / && et ||, je ne connaissais pas cette différence...

Re: Code ne prends pas en compte toutes les lignes

par Ryle » 02 juin 2016, 11:02

@Chaussette : comme suggéré précédemment, je pense qu'il faudrait plutôt que tu parcours les deux fichiers indépendamment l'un de l'autre pour obtenir tous les noms dont tu as besoin et ensuite seulement commencer à les trier :)



@carte-sd : c'est effectivement un problème dans l'expression de la condition :) (enfin pas vraiment un problème puisque sa résolution engendrerait la boucle infinie, mais sa non résolution fait qu'on ne va pas au bout de l'un des fichiers :))

En théorie, la condition de sortie de boucle devrait être lorsque l'on a atteint la fin des deux fichiers :
feof($fp1) && feof($fp2)
On doit donc boucler tant que cette condition est fausse. Cela peut se traduire de deux façon, l'inverse de la condition dans sa globalité, ou l'inverse de chacun des éléments de la condition :
! ( feof($fp1) && feof($fp2) )
!feof($fp1) || !feof($fp2)
Le contraire du ET logique est un OU :). On ne devrait donc pas sortir tant que fichier1 OU fichier2 ne sont pas entièrement lus.


Attention également, en PHP il y a une différence entre les opérateurs AND et &&, ainsi qu'entre OR et || dans la précédence de leur exécution. Les opérateurs && et || sont prioritaires sur les affectations (=, +=, ...) ou l'opérateur ternaire, tandis que AND et OR ne le sont pas. Il est à mon sens préférable d'utiliser les opérateurs && et || (moins explicites qu'en SQL, mais communs à la majorité des langages informatiques) à moins de savoir précisément pourquoi on utilise AND et OR :)

Re: Code ne prends pas en compte toutes les lignes

par Chaussette » 02 juin 2016, 10:09

Bonjour à tous et merci pour vos réponses.

En effet, je n'avais pas fait attention que je partais du principe que $Mot1 était forcément plus petit que $Mot2 et que je comparais que deux mots à la fois.

Pour le problème de la dernière ligne, compter leurs nombres pourrait en effet être une solution !

Je vais essayer tout ça et je reviens vers vous.

Re: Code ne prends pas en compte toutes les lignes

par @rthur » 01 juin 2016, 20:26

Exact bien vu ! ;)

Re: Code ne prends pas en compte toutes les lignes

par or 1 » 01 juin 2016, 18:58

1) file_get_contents() de chacun des fichiers,
2) je met le contenu de chaque ligne dans un tableau avec la fonction explode() (sur le caractère de retour à la ligne \r\n)
plus simple avec http://php.net/manual/fr/function.file.php

Re: Code ne prends pas en compte toutes les lignes

par carte-sd » 01 juin 2016, 17:08

@Ryle
Comment expliquer cela dans ce cas ?

fichier1.txt
antoine
onche
jean
pierre
jeanette
bernard

fichier2.txt
paul
jacques

Code : Tout sélectionner

<?php header('content-type:text/html; charset=utf-8'); $fp1 = fopen('fichier1.txt', 'r'); $fp2 = fopen('fichier2.txt', 'r'); $newFile = fopen('resultat.txt', 'w'); $mot1 = fgets($fp1); $mot2 = fgets($fp2); $mot1 = trim($mot1); $mot2 = trim($mot2); while (!feof($fp1) and !feof($fp2)) { if ($mot1 < $mot2): echo $mot1 . ' < ' . $mot2 . '<br />'; fwrite($newFile, $mot1 . "\r\n"); $mot1 = fgets($fp1); $mot1 = trim($mot1); else: echo $mot1 . ' > ' . $mot2 . '<br />'; fwrite($newFile, $mot2 . "\r\n"); $mot2 = fgets($fp2); $mot2 = trim($mot2); endif; } var_dump(feof($fp1)); // false var_dump(feof($fp2)); // true $mot1 = fgets($fp1); var_dump($mot1); // jeanette fclose($fp1); fclose($fp2); fclose($newFile); echo "Opération terminée"; ?>
D'après mes calculs je devrais avoir une boucle infinie mais PHP sort de la boucle alors que la condition n'est pas vérifiée.

Re: Code ne prends pas en compte toutes les lignes

par Ryle » 01 juin 2016, 15:49

Bonjour,

Le problème de tri vient effectivement du fait que tu compares uniquement deux des mots et que tu considères le premier des deux comme étant le premier de tous en l'inscrivant immédiatement dans ton fichier de sortie. L'écriture dans le fichier ne devrait avoir lieu qu'une fois que tu as comparé ton mot à tous les autres pour être certain qu'il s'agit bien du premier.

@carte-sd : à priori je dirais que tu es bien arrivé au bout de ton fichier :) Ce n'est pas parce que tu n'utilises jamais la valeur "pierre" dans le fichier de sortie que tu n'es pas arrivé à la fin du fichier quand tu as récupéré ce prénom. Fgets() va retourner FALSE quand il arrivera au bout du fichier et afficher ou comparer cette valeur comme s'il s'agissait d'une chaîne revient à tester une chaîne vide (ou la valeur 0 pour du numérique)

A noter également le risque d'une boucle sans fin : si le fichier 1 contient "A" et que le fichier 2 contient "B", "C" et "D", la comparaison permettra de constater que "A" < "B" et écrira donc "A" dans le fichier, puis arrivera au bout du fichier 1. "B" sera ensuite comparé à "" (false retourné par fgets) et si "B" n'est pas inférieur à "", tu vas boucler sans jamais lire le reste du fichier 2

Re: Code ne prends pas en compte toutes les lignes

par carte-sd » 01 juin 2016, 13:59

J'ai trouvé intéressant d'essayer de comprendre pourquoi ton code ne fonctionne pas.
Mes deux fichiers (bien ajouter une ligne vide à la fin de chaque fichier) :

fichier1.txt :
antoine
onche
jean
pierre

fichier2.txt
paul
jacques

Le résultat :
antoine
onche
jean
paul
jacques

Comme on peut le constater ce n'est pas classé par ordre alphabétique.
Le script ($mot1 < $mot2) compare :
antoine avec paul = antoine
onche avec paul = onche
jean avec paul = jean
pierre avec paul = paul
pierre avec jacques = jacques

Ton script trie 2 mots par ordre alphabétique et bug à la fin du fichier.

edit: j'ai remarqué un comportement que je n'arrive pas à expliquer, lorsqu'on arrive à la fin de fichier1 ou fichier2, la variable correspondante vaut '' (une string vide) et la boucle s'arrête, même si il reste des lignes dans l'autre fichier. La condition n'est pas respectée par PHP. Quelqu'un saurait m'expliquer pourquoi ?

Re: Code ne prends pas en compte toutes les lignes

par Spols » 01 juin 2016, 11:52

Pour garder ta manière de faire, je transformerai ta boucle while en une boucle for allant de 0 à la somme des lignes des 2 fichiers (non inclu) . ainsi tu sera sur d'avoir parcouru les 2 fichiers en entier

Re: Code ne prends pas en compte toutes les lignes

par Chaussette » 01 juin 2016, 11:29

Merci pour ta réponse !

C'est donc ça mon problème... Je vais essayer de voir ce que je peux faire.

Je note quand même ta solution, ça pourra toujours me servir en dehors. Merci

Re: Code ne prends pas en compte toutes les lignes

par @rthur » 01 juin 2016, 11:28

Bonjour,

A première vue, je dirai que tu fais une lecture ligne à ligne mais si tes 2 fichiers ne font pas le même nombre de lignes, ta boucle while va s'arrêter dès que tu atteints le fichier la fin du fichier le moins long.

J'ai bien compris que tu utilisais que les fonctions que tu avais vu en cours mais perso si j'avais à faire cela, je ferais:
1) file_get_contents() de chacun des fichiers,
2) je met le contenu de chaque ligne dans un tableau avec la fonction explode() (sur le caractère de retour à la ligne \r\n)
3) je fusionne les tableaux des 2 fichiers en 1 seul avec array_merge()
4) je fait le tri avec sort()
5) je met le résultat obtenu dans le nouveau fichier avec file_put_contents() et implode() (idem avec le caractère \r\n)

Code ne prends pas en compte toutes les lignes

par Chaussette » 01 juin 2016, 11:04

Bonjour à tous!

Je dois préparer un exercice pour mon cours de programmation qui consiste à ordonner deux fichiers par ordre alphabétique. J'ai donc écrit un truc mais le problème c'est qu'il ne lit pas tous les mots de mes fichiers.
Il s'arrête à la lettre P va savoir pourquoi. Est-ce que quelqu'un pourrait m'aider svp ?


PS : je précise que j'ai utilisé des fonctions vues au cours, je sais qu'il y a des raccourcis d'écriture mais je me suis basé exclusivement sur ce que je connaissais :)

Code : Tout sélectionner

<?php $readFile1 = fopen("fichierex1.txt", "r"); $readFile2 = fopen("fichierex2.txt", "r"); $newFile = fopen("fichiersortant.txt", "w"); $Mot1=fgets($readFile1); $Mot1=trim($Mot1); $Mot2=fgets($readFile2); $Mot2=trim($Mot2); $Mot1 = strtr($Mot1, 'ÁÀÂÄÃÅÇÉÈÊËÍÏÎÌÑÓÒÔÖÕÚÙÛÜÝ', 'AAAAAACEEEEEIIIINOOOOOUUUUY'); $Mot1 = strtr($Mot1, 'áàâäãåçéèêëíìîïñóòôöõúùûüýÿ', 'aaaaaaceeeeiiiinooooouuuuyy'); $Mot2 = strtr($Mot2, 'ÁÀÂÄÃÅÇÉÈÊËÍÏÎÌÑÓÒÔÖÕÚÙÛÜÝ', 'AAAAAACEEEEEIIIINOOOOOUUUUY'); $Mot2 = strtr($Mot2, 'áàâäãåçéèêëíìîïñóòôöõúùûüýÿ', 'aaaaaaceeeeiiiinooooouuuuyy'); while(!feof($readFile1) && !feof($readFile2)) { if($Mot1<$Mot2) { fwrite($newFile,$Mot1."\r\n"); $Mot1=fgets($readFile1); $Mot1=trim($Mot1); } else { fwrite($newFile,$Mot2."\r\n"); $Mot2=fgets($readFile2); $Mot2=trim($Mot2); } } fclose($newFile); fclose($readFile1); fclose($readFile2); echo("Opération terminée");
?>