Parsing de fichiers / Filtrage de données

Fermé
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 - Modifié par ryko1820 le 4/01/2014 à 13:00
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 - 21 janv. 2014 à 18:40
Bonjour,

avant d'insérer un fichier en base de données (MySQL) je fais un petit peu de parsing pour constituer à la volée un fichier SQL à partir d'un fichier texte, parsing réalisé en PHP CLI.

Des strings sont passées à une boucle qui les découpe en mots.
Certains mots sont dans une liste d'exclusions (case sensitive et non case sensitive), si les mots sont présents dans cette liste ceux-ci sont rejetés.

actuellement le code dans la boucle est le suivant (j'en suis à une liste de 80 exclusions, soit plus de 160 lignes de code juste pour ça) :

for ($wordCount = 0; $wordCount < count($explodedLine) && $wordCount < 5;$wordCount++) //Je ne garde que les 5 premiers mots
{
  $pos1  = stripos($explodedLine[$wordCount],'titi');
  $pos2  = stripos($explodedLine[$wordCount],'tutu');
  $pos3  = stripos($explodedLine[$wordCount],'tata');
  $pos4  = stripos($explodedLine[$wordCount],'toto');
  $pos5  = strpos($explodedLine[$wordCount],'BLABLA');
  $pos6  = stripos($explodedLine[$wordCount],'XXXXX');

  if (
    $pos1  === false && 
    $pos2  === false && 
    $pos3  === false && 
    $pos4  === false && 
    $pos5  === false && 
    $pos6  === false 
  }
  {    
    $fileName .= $explodedLine[$wordCount] ." ";
  }
}

fwrite($fHndlDest,"INSERT INTO etc ". $fileName ." etc ..." //La requête SQL


Bon, tout fonctionne mais je trouve ça un peu bourrin ... Y aurait-il, une façon plus élégante de procéder ?

Cela ne me dérangerait pas de conserver la liste d'exclusions dans la base de données ou dans un fichier texte par exemple, et de récupérer ces infos dans un tableau transmis ensuite à une fonction "magique" dont j'ignore jusqu'à l'existence ou l'utilisation, mais je vois pas trop comment intégrer cela simplement dans le code.

L'objectif serait d'éviter d'avoir à écrire 400 lignes de code si je dois gérer 200 exclusions.
Ou alors il va falloir que je fasse un script php qui générera cette partie du script php en include par exemple :p

La démarche est peut-être totalement erronée ... Si quelqu'un avait des conseils ...
Merci d'avance pour vos réponses.




You may stop me but you can't stop us all ;-)

3 réponses

mpmp93 Messages postés 6648 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 septembre 2015 1 340
5 janv. 2014 à 00:25
Bonsoir,

Oui ya moyen....

$exclusion = array('toto','tata','titi'.......les autres données.....)

$mot // la variable qui contient le mot à rechercher dans le tableau

if (in_array($mot, $exclusion)) {
echo "j'ai trouvé";
}

C'est in_array qui fera tout.

A+
1
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
Modifié par ryko1820 le 5/01/2014 à 08:41
Merci pour ta réponse, je vais essayer, c'est déjà beaucoup plus facilement gérable.

J'essayerais de voir aussi si en matière de performance c'est mieux, mais comme ça, sans connaitre les performances de la fonction je dirais qu'en plus : "ça se pourrait" :-).

Enfin pour ce script qui n'est lancé qu'à l'initialisation de la bdd, les performances sont secondaires, les insert faits en base ensuite prennant eux, plusieurs secondes :p
.
J'aurais du plus travailler les fonctions des tableaux ...

Je ne sais pas si j'aurais d'autres réponses, mais je laisse le sujet ouvert pour l'instant, au cas ou ...
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
13 janv. 2014 à 12:42
in_array() est pas mal, mais il est uniquement case sensitive et ça, ça me pose problème. Je pensais utiliser faute de mieux un array_map en construisant 2 tableaux à lui soumettre, un pour les exclusions case sensitive, un autre pour les "unsensitive" .

Pas d'autres suggestions Messieurs ? :-)
0
Pitet Messages postés 2826 Date d'inscription lundi 11 février 2013 Statut Membre Dernière intervention 21 juillet 2022 526
13 janv. 2014 à 14:28
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
Modifié par ryko1820 le 13/01/2014 à 18:28
Merci d'avoir cherché, je l'avais vu aussi celui là, mais c'est du tout ou rien et dans mes exclusions j'ai des mots capitalisés ou avec des casses beaucoup plus exotiques ...
Par contre je peux peut être m'en inspirer pour ce que je veux faire ... Je verrais.
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
Modifié par ryko1820 le 19/01/2014 à 21:33
Hello,


J'ai fait d'autres trucs depuis, et là il fallait que je rafraîchisse un peu mes données, alors je me suis replongé la dedans, et voilà ce que ça donne finalement :

(je l'utilise en CLI alors je fais des echo pour logger les actions)

Un fichier PHP pour les exclusions héberge les tableaux pour les blacklist sensitive et case ignore :

/* * * * * * * * * * * * * *
*
*                       File exclusionsList.php
*
*        Liste des exclusions case sensitive et case ignore
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

$caseIgnoreExclusions = array(
    'tutu',
    'toto',
    'tata',
    'titi');

$caseSensitiveExclusions = array(
    'AeGT',
    'GGBf',
    'GOLD',
    'GolD',
    'WV');


J'exploite ça comme ça (n'hésitez pas à critiquer j'apprends) :

class Fileutil
{
  private $caseIgnoreExclusions = array();
  private $caseSensitiveExclusions = array();
  private $needle;
  
  public function __construct()
  {
    include 'exclusionsList.php';
    $this->caseIgnoreExclusions = $caseIgnoreExclusions;
    $this->caseSensitiveExclusions = $caseSensitiveExclusions;    
    $this->needle = "";
  }

  public function parseFile($fileSource,$fileDest)
  {
        $fHndlSource = fopen($fileSource,"r");
 $fHndlDest = fopen($fileDest,"w");
  
 $totalLine = 0;
 $totalWrote = 0;
 $blankLineCount = 0;
 while (!feof($fHndlSource)) {    
     $line = fgets($fHndlSource);
     $totalLine++;

/* ... plusieurs manipulations sans grand intérérêt sur les strings, les mots ...
                 on découpes les phrases, les mots, ça str_replace et ça explode ...  */

      if (strlen($fileName)>1) //pour retirer ligne vides
   {
          // pour logs
          echo "Original sentence = ". trim($fileName) ." \n";
          $add_nl = "";

      // Boucle de traitement des exclusions

    $fileName = "";
    for ($wordCount = 0; $wordCount < count($explodedLine) && $wordCount < 6;$wordCount++) //on ne garde que les 6 premiers mots de chaque string pour sa reconstruction
    {
         $this->needle = $explodedLine[$wordCount];
         

        // C'EST ICI QUE CA SE PASSE !!! :-)
        if (count($this->ar_stripos($this->caseIgnoreExclusions))>0 || count($this->ar_strpos($this->caseSensitiveExclusions))>0) 
         {
              // pour logs
              strlen($add_nl)>0 ? $add_str="" : $add_str = "\tRemoved word(s) : ";
              echo $add_str. $explodedLine[$wordCount] ."  ";
              $add_nl = "\n";
          }
          else
          {
             $fileName .= $explodedLine[$wordCount] ." ";
          }
 }
       echo $add_nl."Final sentence = ". trim($fileName) ." \n===========================================\n";

// ... etc ... Ecriture de mon fichier SQL ...
}
else
   {
    $blankLineCount++;
   }
  }
  fclose($fHndlSource);
  fclose($fHndlDest);
}

// LES 2 FONCTIONS QUI FONT LE BOULOT
  public function ar_stripos($haystack){
        return array_filter(array_map(function($cbArg){
                    return stripos($this->needle , $cbArg);
                    },$haystack),'is_int');
  }
  
  public function ar_strpos($haystack){
        return array_filter(array_map(function($cbArg){
                    return strpos($this->needle , $cbArg);
                    },$haystack),'is_int');
  }
}


Maintenant que je peux gérer plus facilement les exclusions, j'arrive à un taux de filtrage de mes données tout à fait intéressant ... Même si 2/3 "bruits" par-ci, par-là peuvent encore pas être filtrés.

Çà doit être facilement adaptable en procédural.

You may stop me but you can't stop us all ;-)
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
19 janv. 2014 à 20:54
... et merci à ceux qui m'ont donné des pistes :-)
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
19 janv. 2014 à 21:10
J'arrivais pas a passer ma $explodedLine[$wordCount] à mes fonctions et surtout à la callback et j'avais pas envie de créer encore plus de fonctions (et puis je voulais essayer cette syntaxe :p ) alors j'ai créé une propriété "private $needle" pour pouvoir la voir de partout dans la classe, y compris dans les fonctions de callback.
Si quelqu'un s'y connait en portée de variable dans les callback ça m'intéresserait d'avoir son avis.
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
Modifié par ryko1820 le 19/01/2014 à 21:16
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
19 janv. 2014 à 21:46
Au final, sans la propriété pour needle :

Le sujet aurait pu aussi être stripos et strpos utilisant des array en arguments, (fonctions anonymes, array_filter, array_map).

if (count($this->ar_stripos($this->caseIgnoreExclusions,$explodedLine[$wordCount]))>0 || count($this->ar_strpos($this->caseSensitiveExclusions,$explodedLine[$wordCount]))>0) {
              // pour logs
              strlen($add_nl)>0 ? $add_str="" : $add_str = "\tRemoved word(s) : ";
              echo $add_str. $explodedLine[$wordCount] ."  ";
              $add_nl = "\n";
          }
          else
          {
            $fileName .= $explodedLine[$wordCount] ." ";
          }


avec les "use" dans les fonctions


 public function ar_stripos($haystack,$needle){
        return array_filter(array_map(function($cbArg) use ($needle){
                    return stripos($needle , $cbArg);
                    },$haystack),'is_int');
  }
  
  public function ar_strpos($haystack,$needle){
        return array_filter(array_map(function($cbArg) use ($needle){
                    return strpos($needle , $cbArg);
                    },$haystack),'is_int');
  }


0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
Modifié par ryko1820 le 21/01/2014 à 12:27
En fait j'aimerais encore affiner le filtrage, ma blacklist contenant uniquement des mots entiers à exclure.

Exemple, lorsque la string '100' est soumise à la fonction 'ar_strpos' et que le mot '100' est bien dans la liste des exclusions, ok, mais par contre j'aimerais ne pas exclure '10000' qui lui devrait être conservé ...
hummm, je vais essayer d'intégrer un strlen ou un test d'égalité strstr stristr dans la fonction anonyme pour conditionner le return ...

D'ailleur stripos et strpos sont peut être pas les meilleurs candidats finalement ...
0
mpmp93 Messages postés 6648 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 septembre 2015 1 340
Modifié par mpmp93 le 21/01/2014 à 13:25
Bonjour,

une phrase c'est des mots séparés par des 'espace's..... Si on utilise explode comme ceci:

$phrase = " le mot '100' est bien dans la liste des exclusions, ok, mais par contre j'aimerais ne pas exclure '10000' qui...";

si je l'explode en php

$mots = explode(' ',$phrase);


$mots est un tableau. Ensuite, faire des tests de ce genre

foreach($mots AS $key => $mot) {
    if($mot=='100') {
        unset($mots[$key]);
    }
}


et je reconsitute la nouvelle phrase:

$nouvellePhrase = implode(' ', $mots);

qui sera: " le mot '' est bien dans la liste des exclusions, ok, mais par contre j'aimerais ne pas exclure '10000' qui..."

Prévoir un nettoyage de $phrase avant explode

Pour le if dans le foreach, utiliser in_array et un tableau des mots à exclure
....
0
ryko1820 Messages postés 1677 Date d'inscription dimanche 28 avril 2013 Statut Membre Dernière intervention 15 août 2021 276
21 janv. 2014 à 18:40
oui, j'ai essayé, en plus in_array est super rapide, mais pour le coup il est trop strict, à l'arrivée ma blacklist devrait contenir plus d'entrées ... En tout cas en l'état, elle est a refaire :(

Je vais peut être devoir me résoudre à l'utiliser, quite à ne faire que du case sensitive et allonger la liste car à force de rajouter des trucs dans mes fonctions, le traitement dépasse la limite des 30 sec, et ça commence à devenir un peu trop.

c'est dommage parce qu'a part ce gros problème de perf. mes 2 fonctions faisaient exactement ce que je voulais :

for ($wordCount = 0; $wordCount < count($nameArr) && $wordCount < 6;$wordCount++) //on ne garde que les 6 premiers mots de chaque $nameArr 
{
                    // si mot blacklisté trouvé count > 0
                    $isCaseIgnoreWordInBL = count($this->ar_strcasecmp($this->caseIgnoreExclusions,$nameArr[$wordCount]));
                    $isCaseSensitiveWordInBL = count($this->ar_strcmp($this->caseSensitiveExclusions,$nameArr[$wordCount]));
                    
                    if ( $isCaseIgnoreWordInBL===0 || $isCaseSensitiveWordInBL===0) {
                      $printName .= $nameArr[$wordCount] ." ";
                    }
}


Les fonctions :

public function ar_strcasecmp($haystack,$needle)
    {
          return array_filter(array_map(function($cbArg) use ($needle){
                        $result = strcasecmp(trim($needle) , trim($cbArg));
                        if ($result === 0){
                            return $result;                            
                            }
                        },$haystack),'is_int');
    }
  
    public function ar_strcmp($haystack,$needle) 
    {
          return array_filter(array_map(function($cbArg) use ($needle){
                      $result = strcmp(trim($needle) , trim($cbArg));
                      if ($result === 0){
                          return $result;
                        }
                      },$haystack),'is_int');
    }


:'(

En attendant je suis revenu à la version d'avant, car en fait je fais tout ça que pour un mot qui me pose problème alors en attendant d'avoir le courage de me replonger la dedans, je corrigerais à la main.
0