2016-03-23

Application C++ De Numérotation De Lignes De Fichiers

À mes quatre anciens apprenants
si désireux de connaître la programmation.



Le code-source est téléchargeable à l’adresse #01 ou à l’adresse #02.



À une certaine période, lors d’un échange sur un espace de discussion en-ligne, il m’a été demandé si je pouvais écrire un programme C pour numéroter spécifiquement les lignes d’un fichier à plat. Bon, c’est sûr que je n’aime pas les préjugés, mais il me faut avouer que je me suis quand-même laissé tomber dans le piège d’un certain préjugé. Ah!, pas facile de vaincre les préjugés.

Il est évident que la manière dont la chose me fut demandée m’a laissé penser qu’il s’agissait d’une provocation ou peut-être d’une mise à l’épreuve. Aussi le problème me paraissait simple à traiter et j’étais convaincu -d’après les échanges- que le demandeur lui-même était bien capable de réaliser ce qu’il demandait; ce qui peut expliquer sans le justifier le préjugé dont j’ai parlé à l’instant. Je n’ai donc pas accordé d’importance à cette requête…jusqu’à dernièrement. Judicieusement au cours d’une certaine activité, la question m’est revenue avec plus d’intérêt et plus d’intensité et j’ai alors décidé d’écrire quelques lignes de code en C++ natif pour créer cet outil.

Opérations fondamentales

Dans un premier temps, la réflexion a consisté à affecter systématiquement un numéro naturel à chaque ligne de fichiers, du début jusqu’à la fin. Ainsi la énième ligne aura le numéro ‘n’ dans la chronologie de comptage naturel.

Le procédé est constitué par les opérations fondamentales que sont: l’ouverture du fichier d’entrée; la lecture ligne par ligne de ce fichier; la génération d’une chaîne de caractères dont le contenu est le numéro correspondant à chaque ligne suivi de la ligne lue; la création et/ou l’ouverture d’un fichier de sortie et l’écriture dans ce fichier de chaque ligne recomposée.

L’application FLApp.exe

Le code de l’application FLApp est un tout monolithique dans lequel on ne s’embarrasse même pas de faire des séparations fonctionnelles.

Une variable est créée avec pour rôle de conserver le nom du fichier à lire, donné par l’utilisateur. L’ouverture du fichier-source ou fichier d’input/entrée est faite avec une petite phase de détection d’erreur qui signale l’incapacité à ouvrir le fichier due à son inexistence ou à une erreur dans sa dénomination. Et dans ce cas fatal, le processus s’arrête là. L’extrait de code est:

sprintf(A_File, argv[1]);
...
FILE *Recordz_1, *Recordz_2;
...
if ( (Recordz_1 = fopen(A_File, "r")) == NULL )
{
   printf("%s file not found. Are you missing the right file?\n", A_File);
   return EXIT_FAILURE;
}

Une fois le fichier ouvert, il est lu jusqu’à la rencontre-connaissance-salutation d’usage avec EOF (End Of File) -«Salut, moi on m’appelle End Of File et j’habite à la fin d’un fichier.», «Ah d’accord, c’est vous? Enchanté de vous connaître!», etc- hia, hia, hiaah. La lecture est réalisée dans une boucle while dont la condition d’arrêt est donc la rencontre de EOF. Alors si EOF est trouvé, la fonction fgets renvoie NULL et c’est terminé -«Hé, pst; des fois moi-aussi j’ai envie de quitter la fin du fichier pour sortir faire un petit tour. Pourriez pas m’aider, là?»-, lol.

Le numéro correspondant (qui avance chaque fois d’une unité) est placé au début d’une variable-tampon et le contenu de la ligne lue est ajouté pour former un tout complet. Cette variable-tampon est à chaque nouvelle lecture remise à vide. La portion de code correspondante est:

while((fgets(OrigStr, 256, Recordz_1)) != NULL)
{
   ...
   snprintf(DestStr, 255, "", "");

   ++Counter;
   sprintf(DestStr, "%d ", Number);
   Number++;

   sprintf(DestStr, "%s%s", DestStr, OrigStr);
   ...
}

Une fois la variable-tampon nourrie, son contenu est écrit dans le fichier de destination. La même opération est répétée pour toutes les lignes du fichier d’origine.

while((fgets(OrigStr, 256, Recordz_1)) != NULL)
{
   ...
   fputs(DestStr, Recordz_2);
   fflush(Recordz_2);
}

À la fin de la lecture et en conséquence de l’écriture, on procède à la fermeture des deux fichiers avec fclose et à la libération des zones-mémoires allouées aux variables de chaînes de caractères.

...
if (Recordz_2) fclose(Recordz_2);
if (Recordz_1) fclose(Recordz_1);

free( (void*) OrigStr);
free( (void*) DestStr);

Et c’est tout.

Exécution simple de l’application FLApp.exe

Pour exécuter le programme, l’utilisateur a besoin de taper dans une fenêtre de commandes, la ligne ci-après: FLApp <Fichier1> [Fichier2]
où Fichier1 est le fichier-source obligatoire et Fichier2 est le fichier-destination facultatif. Si le fichier-destination n’est pas fourni, un fichier-destination (pré-indiqué dans le code) est créé et/ou ouvert automatiquement. Il apparaît que le nombre d’arguments minimal est alors de deux (02).

Exemple: FLApp FLAppMain.cpp

En conséquence, le fichier-destination montre qu’on a maintenant un numéro séquentiel devant chaque ligne du fichier.



FLApp: Exécution et fichier de sortie avec numéros non alignés unités sous unités, dizaines sous dizaines

Ce qui précède représente ce qui dans un premier temps constituent les différentes parties d’un ensemble condensé. Dans un second temps, la réflexion a été de faire des blocs fonctionnels qui peuvent éventuellement être mis dans des modules s’il en est besoin.

Fonctionnalités évoluées de la deuxième (2ième) version

On peut aisément se rendre compte que la fonctionnalité de FLApp est très basique, ce qui est loin d’être un tort. Toutefois en seconde réflexion, j’ai pensé à "étendre" et "enrichir" l’application. Dans cette joyeuse perspective, la nouvelle version donne à l’utilisateur le loisir d’indiquer la ligne à partir de laquelle le numérotage doit commencer et la ligne où cette numérotation doit s’arrêter. L’utilisateur a aussi la possibilité d’indiquer à partir de quel chiffre/nombre la numérotation doit démarrer. Ce chiffre qui est par défaut '1' peut maintenant être '22', '101', or whatever, comme le disent les anglophones. Il a donc fallu augmenter les paramètres de l’application et pourvoir les instructions y relatives. Par ailleurs il y a l’opportunité offerte de fractionner une ligne jugée trop longue avec le rappel du numéro de la ligne principale.

Contrairement à la première version donc, le nombre de paramètres/arguments passe à sept (07); le nombre minimal étant toujours deux (02). Ce code le montre:

...
    if (argc < 2 or argc > 7)
    {
       printf("\nMinimum of 2 to maximum of 7 parameters authorised.\n");
       InformUser('G', argv[0]);
       return EXIT_FAILURE;
    }
...

Comme stipulé plus haut, cette fois-ci les instructions ont été rassemblées en fonctions ou méthodes dans un but didactique d’abord et aussi par souci de cohésion, de clarté, d’harmonie.

La partie substantielle de cette nouvelle version est la fonction portant le nom du programme joliment renommé FiLiP.

short FiLiP(char* _InFile, char* _OutFile, UINT _Bounds[], UINT _Cardinals[])
{
  FILE *InFile, *OutFile;

  char Buffer[LINESIZE] = "\n";
  char *InStr, *StrBuffer, *PolyStr;
  char *OutStr = NULL;

  bool ReAdjustIt = false;

  if ( _Cardinals[0] > _Cardinals[1] ) ReAdjustIt = true;

  if (stricmp(_OutFile, "") == 0)
  {
    strncpy( _OutFile, _InFile, (strrchr(_InFile, '.') - /*&*/_InFile) );
    strcat(_OutFile, "_FiLiPed.txt");
  }

  printf("\nTrying to open %s >>>\n", _InFile);
  if ( (InFile = fopen(_InFile, "r")) == NULL )
  {
     printf("Failure. Can't open %s.\n", _InFile);
     return (short) EXIT_FAILURE;
  }
  printf("%s successfully opened.\n", _InFile);

  InStr = (char*) malloc(LINESIZE);
  UINT LineNum = _Bounds[0], LineCtr = /*1*/0, Bound = _Bounds[0];
  OutStr = (char*) malloc(LINESIZE);

  printf("Reading %s >>>\n", _InFile);
  printf("Executing the appropriate operation for %s >>>\n", _OutFile);

  if ( (OutFile = fopen(_OutFile, "a+")) == NULL )
  {
     if(InFile) fclose(InFile);
     printf("Can't operate %s.\n", _OutFile);
     return (short) EXIT_FAILURE;
  }
  printf("%s successfully opened.\n", _OutFile);

  UINT SubSectionsTotal = 0;

  while( (StrBuffer = fgets(InStr, LINESIZE, InFile)) != NULL )
  {
 UINT SubSectionsNbr = 0;
 UINT Llen = strlen(InStr);

 char *NullCharPtr = NULL;
      bool WriteNum = false;

      NullCharPtr = strchr(InStr, '\0');
 UINT Posicator = 0;

 //The printf() and related functions are supposed to memset() variables somehow for us.
 //So I don't make the specific call: memset((void*)OutStr,0,sizeof(OutStr)) (Am I mistaken, please help me GOD!)
 snprintf(OutStr, (LINESIZE - 1), "", "");

 //If the end line value should be adjusted, we repeatedly increase it by one each time LineCtr reaches it.
 //Again this is for flexibility otherwise we will impose rule to the user.
 if ( ReAdjustIt ) ++_Cardinals[1];
 if ( _Bounds[1] == 0 ) Bound++;
 else Bound = _Bounds[1];

 ++LineCtr;

 if ( (LineCtr >= _Cardinals[0] && LineCtr <= _Cardinals[1]) && (LineNum <= Bound) )
 {
         sprintf(OutStr, "[%0.3d] ", LineNum);
    LineNum++;
    WriteNum = true;
    }

      //We have the following code included in for an attempt to handle the null terminating character (\0) inside a string
      //If not required in your case, just remove the code delimited by //////*/, and replace it with the following:
      //--> sprintf(OutStr, "%s%s", OutStr, InStr);
      //////*/ 
 do
 {
    if (NullCharPtr == NULL)
    {
       if (Posicator == 0)
      {
       sprintf(OutStr, "%s%s", OutStr, InStr);
    }
    else
    {
      for (int i = Posicator - 1; i++ < Llen; sprintf(OutStr, "%s%c", OutStr, InStr[i]));
       }
    break;
    }
   
    for (int i = Posicator - 1; i++ < (NullCharPtr - InStr -1); sprintf(OutStr, "%s%c", OutStr, InStr[i]));
    Posicator = (NullCharPtr - InStr);
    NullCharPtr = strchr(NullCharPtr+1, '\0');
 }while( (Posicator >= 0 and Posicator < Llen) );
 //////*/ 

   //Call to MakeSections() if needed.
   //This is not necessary. If one doesn't want to have a line divided in sections then let her/him not make this call.
   //So comment or remove this if you don't need it.
   PolyStr = MakeSections(OutStr, 88, LineNum, WriteNum, &SubSectionsNbr);
   //Call to MakeSections() again?

   strcpy(OutStr, PolyStr);
   if ( LineCtr == 1 ) printf("Writing to %s >>>\n", _OutFile);
   fputs(OutStr, OutFile);
   fflush(OutFile);

   SubSectionsTotal = SubSectionsTotal + SubSectionsNbr;
   }

  printf("%s reading finished.\n", _InFile);
  printf("Finished writing to %s.\n", _OutFile);

  printf("Closing file >>>\n");
  if (OutFile) fclose(OutFile);
  printf("\n%s closed.\n_____________________________________________________\n\n", _OutFile);

  printf("Closing file >>>\n");
  if (InFile) fclose(InFile);
  printf("\n%s closed.\n_____________________________________________________\n\n", _InFile);

  StrBuffer = NULL;
 
  free( (void*) InStr);
  free( (void*) OutStr);

  //Is this necessary???
  InStr = NULL;
  OutStr = NULL;
  InFile = NULL;
  OutFile = NULL;

  DisplayInfo(LineCtr+SubSectionsTotal, (LineNum - _Bounds[0]));
  return (short) EXIT_SUCCESS;
}

Par défaut les numéros générés ne sont pas précédés de zéros non significatifs, c.-à-d. qui ne changent pas la valeur d’un chiffre/nombre. Mais si vous avez lu l’article sur l’alignement des nombres, unités sous unités, dizaines sous dizaines, vous saurez pourquoi j’ai changé le format des numéros. De manière programmatique dans C++, cela se fait avec l’utilisation du format %0.nd; n étant le nombre de positions recherché. Notez qu’il n’est pas obligé que les numéros soient entre crochets ([,]). Dans notre programme, on a ceci:

...
sprintf(OutStr, "[%0.3d] ", LineNum);
...

En outre, dans une tentative de résolution du problème improbable de caractère nul, le code suivant a été inséré:

do
{
   if (NullCharPtr == NULL)
   {
      if (Posicator == 0)
      {
         sprintf(OutStr, "%s%s", OutStr, InStr);
      }
      else
      {
         for (int i = Posicator - 1; i++ < Llen; sprintf(OutStr, "%s%c", OutStr, InStr[i]));
      }
      break;
   }
   for (int i = Posicator - 1; i++ < (NullCharPtr - InStr -1); sprintf(OutStr, "%s%c", OutStr, InStr[i]));
   Posicator = (NullCharPtr - InStr);
   NullCharPtr = strchr(NullCharPtr+1, '\0');
}while( (Posicator >= 0 and Posicator < Llen) );

L’idée est la suivante: détecter le caractère nul dans la ligne; copier tous les caractères se trouvant avant; remettre le caractère nul dans sa position puis faire suivre le reste des caractères s’il y en a, prouvant ainsi que le caractère nul ne marque pas la fin de la ligne. Cette copie, dont d’autres similitudes se rencontrent dans le programme, se fait fondamentalement grâce à l’instruction qui tient sur une seule ligne que voici:

...
for (int i = Posicator - 1; i++ < (NullCharPtr - InStr -1); sprintf(OutStr, "%s%c", OutStr, InStr[i]));
...

J’ai l’impression de vous entendre dire «Fhm, ce code sent.» et je m’empresse de reprendre pour vous la chanson qui dit ceci: «♪Façon ça sent ♩mauvais là, c’est comme ça ♪ c’est doux! ♬». Mais je dois quand même demander à mon frère de la Côte d’Ivoire, David Tayorault, de bien vouloir faire attention à ne pas chanter des choses pareilles dans des oreilles d’enfant. <:-(

Quant à la coupure d’une ligne en sous-lignes avec inclusion du numéro de ligne principale ou non, la fonction qui en est responsable est:

char* MakeSections(char *StrPtr, UINT StrSize, UINT LineNumVal, bool WriteNumVal, UINT* SectionsNbrVal)
{
 //72 minimum characters line is an arbitrary chosen number.
 //Please feel free to set any other number that fits your homework/officework needs.
 if ( (StrSize > strlen(StrPtr)) || StrSize < 72 ) return StrPtr;

 UINT MaxCharLen = strlen(StrPtr) + 1;
 char EvalStr[MaxCharLen], OffStr[MaxCharLen], SectionStr[StrSize + 1];
 char *SpaceCharPtr = "\0";

 *EvalStr = '\0';
 SectionStr[StrSize] = '\0';

 char *FinalStr = new char[2 * MaxCharLen];
 *FinalStr = '\0';

 strcpy(EvalStr, StrPtr);
 int RightSize, CharsSegment;

 USHORT Limit_i;
 UINT SectionsCount = 0;
 bool FirstRound = true;

  do
  {
    *OffStr = '\0';//sprintf compatible.

    if ( strlen(EvalStr) < StrSize )
    {
      strcpy(SectionStr, EvalStr);
      goto FinalStrPrint;
    }

    strncpy(SectionStr, EvalStr, StrSize);
    for(Limit_i = StrSize - 1; Limit_i++ < strlen(EvalStr); sprintf(OffStr, "%s%c", OffStr, EvalStr[Limit_i]));

    if (SectionStr[StrSize - 1] != ' ')
    {
      SpaceCharPtr = strrchr(SectionStr, ' ');

      CharsSegment = (SpaceCharPtr - SectionStr);
      RightSize = (2 * CharsSegment) - StrSize;
      if ( (SpaceCharPtr != NULL) && (RightSize >= 0) )
      {
        *OffStr = '\0';
        SectionStr[CharsSegment + 1] = '\0';
        strncpy(SectionStr, SectionStr, CharsSegment + 1);
        for(Limit_i = (SpaceCharPtr - SectionStr); Limit_i++ < strlen(EvalStr); sprintf(OffStr, "%s%c", OffStr, EvalStr[Limit_i]));
      }
    }
    strcpy(EvalStr, OffStr);
    FinalStrPrint:
    if (FirstRound == true)
    {
      strcpy(FinalStr, SectionStr);
      FirstRound = false;
      continue;
    }

    if (WriteNumVal) sprintf(FinalStr, "%s\n\t[%0.3d cont'd] %s", FinalStr, LineNumVal-1, SectionStr);
    else sprintf(FinalStr, "%s\n\t%s", FinalStr, SectionStr);
    *SectionsNbrVal = ++SectionsCount;
  }while( strlen(OffStr) != 0);

 return FinalStr;
}

WriteNum à true signifie qu’on veut que le numéro de ligne initiale soit repris pour les sections de la ligne.

Utilisation de l’application FiLiP.exe

Exemple basique

Pour utiliser ce nouveau programme retravaillé, l’utilisateur peut, dans une fenêtre de commandes, saisir le plus simplement la ligne qui suit: FiLiP /F:FilipMain.cpp (suivie de [Entrée])

Le résultat de cette exécution peut se voir dans le fichier de sortie.



FiLiP: Exécution basique et fichier de sortie

On peut voir par exemple que la ligne ayant le numéro entre crochets [088] continue sur la ligne suivante avec le numéro qui est repris, signifiant que c’est la ligne précédente qui continue.

Autres exemples

Pour commencer à numéroter à partir de la vingt-deuxième (22ième) ligne en démarrant à cent (100), l’utilisateur saisira: FiLiP /F:FilipMain.cpp /O:FiLiP.txt /X:100 /A:22



FiLiP: Commande de numérotage à compter de la ligne 22 et fichier de sortie.

La ligne 22 est la première à être numérotée avec ‘100’ comme numéro de départ.

Si l’utilisateur ne souhaite numéroter qu’une et une seule ligne, disons la ligne soixante-neuf (69); et on se demande bien pourquoi, il tapera: Filip /f:FilipMain.cpp /O:FiLiP.txt /X:69 /A:69 /B:69
ou bien: Filip /f:FilipMain.cpp /o:FiLiP.txt /X:69 /Y:69 /A:69



FiLiP: Commande de numérotation d’une ligne unique et fichier de sortie.

Ici, la seule ligne numérotée est la ligne portant le numéro 69, comme souhaité par l’utilisateur pervers qui ne pense tout le temps qu’à ça. lol :-))]

Si l’utilisateur souhaite numéroter de 1 à 50 seulement l’intervalle de lignes 51 à 100 (on parle de numéro d’ordre, là), il tapera: Filip /F:FilipMain.cpp /O:FiLiP.txt /A:51 /B:100



FiLiP: Commande de numérotation de l’intervalle de lignes 51 à 100 et fichier de sortie.

Pour numéroter le même intervalle de lignes 51 à 100 mais en commençant le numérotage à 51, l’utilisateur a la possibilité de saisir: Filip /F:FilipMain.cpp /O:FiLiP.txt /X:51 /A:51 /B:100


Image : Fenetre de commande et resultat
FiLiP: Commande de numérotation de l’intervalle de lignes 51 à 100 commençant à 51 et fichier de sortie.

On peut voir qu’ici le premier numéro est ‘51’ alors que dans le cas précédent la numérotation commence par le numéro ‘1’ à partir de la ligne 51.

Les différents cas qui précèdent montrent que ce sont des exemples-types qui peuvent avoir d’autres variantes selon les besoins de l’utilisateur lambda. On peut même effectuer plusieurs numérotations pour les mêmes données si on considère le fait qu’un fichier-destination (fichier de sortie) peut être à son tour utilisé comme fichier-source (fichier d’entrée). En outre, on peut décider dans le code que les numéros soient des numéros pairs, impairs, ou des nombres premiers.

Remarques

  • On remarquera que le zéro (0) utilisé avec le paramètre /Y ou /B a le sens de "continuer jusqu’à la fin".
  • Une technique a été utilisée pour obliger le paramètre /F (ou /f) à être le premier paramètre fourni (après le nom de l'application). Si l’utilisateur tente de changer de place à ce paramètre, l’application lui retourne un message d’erreur. On pourrait faire la même chose pour tous les autres paramètres mais on s’est limité ici juste au paramètre de fichier d’input à titre d’illustration.
  • La fonction de coupure de lignes est active par défaut, c.-à-d. qu’elle est non commentée. Si on veut la désactiver, il faut commenter l’instruction d’appel correspondante. On peut toutefois aussi la contourner en indiquant une grande valeur, comme mille (1000).
  • Lorsque vous exécutez le programme sur son fichier-source, FilipMain.cpp, avec la fonction de sectionnement de lignes, MakeSections(), vous serez peut-être étonné du résultat mais faut pas l’être. Dans le code il y a des espaces et des tabulations qui ne valent pas la même chose, alors les sections coupées peuvent donner l’impression que la fonction MakeSections() est capricieuse.
  • Dans la version que j’utilise, il y a un paramètre /Q qui permet de demander à l’application de s’exécuter de façon silencieuse (quiet), sans produire certaines informations d’exécution telles que "Opening file". Ce qui amène à avoir dans le code des instructions du genre:

    if (!QuietVal) printf("Closing file >>>\n");
    


    FiLiP: Commande avec paramètre /Q.

    Le seul message dont l’affichage est autorisé est celui relatif aux nombres de lignes numérotées par rapport à celles écrites. Je répète: ceci n’est pas disponible dans la version à télécharger.

Exercices

Il y a bien de choses à améliorer dans cette application, vous vous en doutez. Cette fois-ci, il vous appartiendra de faire ces améliorations. Quoi, vous geignez? Croyez-vous donc que c’est à moi seul de travailler? Non, bande de faignants! Fermez donc votre instrument à protester et mettez-vous au travail. Fissa!

Exo 1: D’abord, vous allez commencer par ajouter un paramètre qui permet à l’utilisateur d’indiquer le nombre de caractères à partir duquel une ligne est considérée trop longue et qu’il faut la sectionner/fractionner.

Exo 2: Le type utilisé pour les chaînes de caractères est le "char" (de l’anglais character). Vous allez produire un autre programme qui utilise le type tchar avec les fonctions et macros correspondantes.

Exo 3: Comme dit plus haut, dans la version que j’utilise il y a un paramètre /Q (ou /q) qui met l’application en mode silencieux pour ainsi dire. Il vous est demandé d’inclure un tel paramètre dans le programme FiLiP.

Exo 4: L’exercice suivant que vous aurez à faire, c’est d’interdire l’utilisation de la valeur zéro (0) avec un paramètre. Il est actuellement possible de mettre /x:70 /y:0 dans une commande. Il faut rendre cela impossible.

Exo 5: Dans le code, on aimerait bien que l’incrémentation du compteur de ligne soit changée. Cela exigera une modification conséquente dans l’évaluation d’une condition. Peut-être un AND (&&) devra être remplacé par un OR (||); à vous de voir. Mais si vous regardez bien dans le code, il y a un indice que j’ai laissé exprès pour vous. Ça devrait donc être facile.

Exo 6: Pour couper une ligne trop longue en deux ou plus, la longueur de la ligne est évaluée après l’insertion de son numéro. Vous êtes appelé à modifier le code pour qu’une ligne soit évaluée avant l’ajout du numéro.

Exo 7: Il y a dans le code un test conditionnel, avec la structure if, pour évaluer le caractère indicatif de la présence d’un paramètre: le slash "/", le tiret "-" ou autre. Il s’agit dans cet exercice-ci de changer la structure if par une structure switch.

Exo 8: L’appel de la méthode d’information pour l’utilisateur est suivi d’une instruction de retour-échec (return EXIT_FAILURE). Il vous est demandé de modifier la méthode pour qu’on n’ait plus à l’accompagner de l’instruction de retour. Pour cela, on peut penser que l’appel de cette méthode correspond à une situation d’échec du programme.

Exo 9: Pour laisser le fichier-source intact, le résultat de l’application est placé, comme vous le voyez, dans un fichier de sortie. Mais on peut décider de faire le travail de numérotage directement dans le fichier-source lui-même. C’est ce qui vous est demandé dans cet exercice. On peut voir ça de la manière suivante: on récupère une ligne dont on évalue le nombre exact de caractères, on procède à un effacement en arrière de ce même nombre de caractères à partir de la position du curseur (simulation de backspace) et on recopie la variable-tampon à cet emplacement.

Bon, ça paraît beaucoup mais ce sont de petits exercices auxquels j’ai d’ailleurs déjà répondu d’une façon ou d’une autre.

Conclusion

Voilà cher lecteur, j’ai le plaisir de vous donner cet outil que moi-même j’utilise pour numéroter les lignes de fichiers. Il s’agit d’une application C++ mais qui emploie des instructions semblables ou ayant une proche équivalence dans le langage C. J’imagine donc que toute personne ayant des notions de C qui le désire peut aisément convertir cette appli en C pur; moi pour le moment ça me suffit que ce soit en C++. Le jour où ce serait indispensable de l’avoir en C ou en assembleur, on va s’y atteler courageusement mais pour vous dire la vérité, j’espère ne pas avoir à le faire. lol

Allez, bien de choses à vous. Bonne programmation et à la prochaine.

© Copyright United Kingdom of Love - Tous droits réservés.

Aucun commentaire: