Consolidation des pages les plus visitées avec lex

De Wicri Outils

On désire consolider des pages contenant des informations issues des pages Special:Pages_les_plus_visitées d'un wiki sous MediaWiki. Sur ce wiki, en faisant un copier coller, on obtient des lignes telles que :

# Accueil ‎(267 consultations)
# MediaWiki et SVG ‎(67 consultations)

On veut faire de même sur plusieurs wikis afin de générer la partie pages les plus visitées des statistiques de Wicri. Voir par exemple :

Préparation manuelle des données

Pour réaliser l'application on va d'abord constituer manuellement un fichier qui concatène plusieurs listes de consultations, chacune étant préfixée par un lien interwiki. (Pour connaître la liste des liens interwikis, voir Special:Interwiki).

Par exemple :

[[ticri-outils.fr:Accueil|Ticri outils (fr)]]
# Accueil ‎(267 consultations)
# MediaWiki et SVG ‎(67 consultations)
[[ticri.fr:Accueil|Ticri (fr)]]
# DC 2009 Séoul ‎(6 311 consultations)
# Accueil ‎(3 585 consultations)
[[ticri.en:Main Page|Ticri (en)]]
# Main Page ‎(920 views)
# DC 2009 Seoul ‎(645 views)
[[pool:Main Page|Wicri Média]]
# Main Page ‎(1,646 views)
# Accueil ‎(1,031 views)

On désignera ce fichier par sample.txt

Analyse des données

Un examen du fichier par la commande shell «  od -c < sample.txt  » montre une difficulté illustrée par le résultat suivant :

0000000    [   [   t   i   c   r   i   -   o   u   t   i   l   s   .   f
0000020    r   :   A   c   c   u   e   i   l   |   T   i   c   r   i    
0000040    o   u   t   i   l   s       (   f   r   )   ]   ]  \n   #    
0000060    A   c   c   u   e   i   l     342 200 216   (   2   6   7    
0000100    c   o   n   s   u   l   t   a   t   i   o   n   s   )  \n

On constate la présence d'un caractère UTF 8, constitué des 3 codes octal « 342 200 216 » avant la parenthèse introduisant le nombre de visites.

Remplacement des caractères invisibles de l'UTF 8

Pour obtenir un fichier plus lisible, on va réaliser un premier programme step0.lex, élémentaire avec une seule règle de substitution.

%{
#include <stdio.h>
#include <stdlib.h>
%}
%%
\342\200\216  putchar('!');
%%
main()
{
  yylex();
}

Pour compiler et exécuter on fait simplement

lex step0.lex 
gcc lex.yy.c -ll -o step0
./step0 < sample.txt

On obtient comme résultat :

[[ticri-outils.fr:Accueil|Ticri outils (fr)]]
# Accueil !(267 consultations)
# MediaWiki et SVG !(67 consultations)
[[ticri.fr:Accueil|Ticri (fr)]]
# DC 2009 Séoul !(6 311 consultations)
# Accueil !(3 585 consultations)
[[ticri.en:Main Page|Ticri (en)]]
# Main Page !(920 views)
# DC 2009 Seoul !(645 views)

Insertion du lien interwiki en tête de chaque ligne

On veut transformer le fichier précédent pour obtenir :

# [[ticri-outils.fr:Accueil|Ticri outils (fr)]] Accueil !(267 consultations)
# [[ticri-outils.fr:Accueil|Ticri outils (fr)]] MediaWiki et SVG !(67 consultations)
# [[ticri.fr:Accueil|Ticri (fr)]] DC 2009 Séoul !(6 311 consultations)
# [[ticri.fr:Accueil|Ticri (fr)]] Accueil !(3 585 consultations)
# [[ticri.en:Main Page|Ticri (en)]] Main Page !(920 views)
# [[ticri.en:Main Page|Ticri (en)]] DC 2009 Seoul !(645 views)

Pour cela il faut traiter de façon séparée les lignes qui commencent par un crochet ouvrant. La première règle repère un crochet en début de ligne et déclenche un changement d'état (BEGIN WIKI;).

Dans l'état WIKI on se contente de recopier chaque caractère différent d'un saut-de-ligne dans la zone de texte repérée par le pointeur « wikiLink » (noter la déclaration en amont comme variable globale et le malloc() en début de programme principal.

%{
#include <stdio.h>
#include <stdlib.h>
char *wikiLink;
%}
%START WIKI
%%
^\[       { strcpy(wikiLink, yytext); 
          BEGIN WIKI;}
<WIKI>.   strcat(wikiLink,yytext);
<WIKI>\n  BEGIN 0;
^\#       printf ("# %s", wikiLink);
%%
main()
{
  wikiLink=malloc(200);
  yylex();
}

Extraction du nombre de visites en vue d'un tri

On veut maintenant recopier le nombre de visites en début de ligne pour en faire une clé de tri qui sera séparée de la ligne par une tabulation.

On va utiliser un programme lex à deux états Z1 et NUM. Z1 traite le début de ligne jusqu'au nombre de visites. Il sera rangé dans une chaine z1.

Dans l'état NUM, on élimine l'espace ou la virgule qui repère les milliers de la clé de tri.

%{
#include <stdio.h>
#include <stdlib.h>
  char *num;
  char *z1;
%}
%START Z1
%START NUM
%%
<Z1>"!("/[0-9]   {strcat(z1,yytext);
                  strcpy(num,"");
                  BEGIN NUM;}
<Z1>.            strcat(z1,yytext);
<NUM>[0-9]+      {ECHO;
                  strcat(num,yytext);}
<NUM>[, ]/[0-9]  strcat(num,yytext);
<NUM>[ ]        {printf("\t%s%s ",z1,num); 
                 BEGIN 0;}
\n              {ECHO; strcpy(z1,""); 
                 BEGIN Z1;}
%%
main()
{
  z1=malloc(200);
  num=malloc(100);
  strcpy(z1,"");
  BEGIN Z1;
  yylex();
}

Pour obtenir un fichier trié, on lance la ligne de shell :

./step0 < sample.txt | ./step1 | ./step2 | sort -rn

On obtient alors :

6311	# [[ticri.fr:Accueil|Ticri (fr)]] DC 2009 Séoul !(6 311 consultations)
3585	# [[ticri.fr:Accueil|Ticri (fr)]] Accueil !(3 585 consultations)
920	# [[ticri.en:Main Page|Ticri (en)]] Main Page !(920 views)
645	# [[ticri.en:Main Page|Ticri (en)]] DC 2009 Seoul !(645 views)
267	# [[ticri-outils.fr:Accueil|Ticri outils (fr)]] Accueil !(267 consultations)
67	# [[ticri-outils.fr:Accueil|Ticri outils (fr)]] MediaWiki et SVG !(67 consultations)

Mise en page finale

Pour la mise en page finale, il faut :

  • éléminer la clé de tri (règles de l'état KEY),
  • recopier le lien interwiki pour générer un lien sur le nom de page, (état LINK)
  • recopier le nom de la page visitée (état PAGE)
%{
#include <stdio.h>
#include <stdlib.h>
  char *interWikiLink;
  char *page;
%}
%START KEY
%START LINK
%START PAGE
%%
<KEY>\t   BEGIN 0;
<KEY>.   ;
"# [["      {strcpy (interWikiLink,""); 
             printf("# \'\'\'\[\[");
             BEGIN LINK;}
<LINK>":"    {ECHO; BEGIN 0;}
<LINK>.      {ECHO;
             strcat (interWikiLink,yytext);}
"]] "       {printf("\]\] \'\'\' : \[\[%s:", interWikiLink);
              strcpy(page,"");
             BEGIN PAGE;}
<PAGE>" !("  {printf("|%s\]\] (", page); BEGIN 0;}
<PAGE>.      {ECHO;
             strcat (page,yytext);}
\n         {ECHO; BEGIN KEY;}
%%
main()
{
  interWikiLink=malloc(100);
  page=malloc(1000);
  BEGIN KEY;
  yylex();
}

Le résultat est alors :

# '''[[ticri.fr:Accueil|Ticri (fr)]] ''' : [[ticri.fr:DC 2009 Séoul|DC 2009 Séoul]] (6 311 consultations)
# '''[[ticri.fr:Accueil|Ticri (fr)]] ''' : [[ticri.fr:Accueil|Accueil]] (3 585 consultations)
# '''[[ticri.en:Main Page|Ticri (en)]] ''' : [[ticri.en:Main Page|Main Page]] (920 views)
# '''[[ticri.en:Main Page|Ticri (en)]] ''' : [[ticri.en:DC 2009 Seoul|DC 2009 Seoul]] (645 views)
# '''[[ticri-outils.fr:Accueil|Ticri outils (fr)]] ''' : [[ticri-outils.fr:Accueil|Accueil]] (267 consultations)
# '''[[ticri-outils.fr:Accueil|Ticri outils (fr)]] ''' : [[ticri-outils.fr:MediaWiki et SVG|MediaWiki et SVG]] (67 consultations)

Soit :

  1. Ticri (fr)  : DC 2009 Séoul (6 311 consultations)
  2. Ticri (fr)  : Accueil (3 585 consultations)
  3. Ticri (en)  : Main Page (920 views)
  4. Ticri (en)  : DC 2009 Seoul (645 views)
  5. Ticri outils (fr)  : Accueil (267 consultations)
  6. Ticri outils (fr)  : MediaWiki et SVG (67 consultations)