Parsing de fichiers / Filtrage de données
ryko1820
Messages postés
1878
Statut
Membre
-
ryko1820 Messages postés 1878 Statut Membre -
ryko1820 Messages postés 1878 Statut Membre -
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) :
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 ;-)
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 ;-)
A voir également:
- Parsing de fichiers / Filtrage de données
- Fuite données maif - Guide
- Supprimer les données de navigation - Guide
- Explorateur de fichiers - Guide
- Gestionnaire de fichiers - Télécharger - Gestion de fichiers
- Renommer des fichiers en masse - Guide
3 réponses
Bonsoir,
Oui ya moyen....
C'est in_array qui fera tout.
A+
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+
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 :
J'exploite ça comme ça (n'hésitez pas à critiquer j'apprends) :
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 ;-)
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 ;-)
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.
Si quelqu'un s'y connait en portée de variable dans les callback ça m'intéresserait d'avoir son avis.
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).
avec les "use" dans les fonctions
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');
}
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 ...
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 ...
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 est un tableau. Ensuite, faire des tests de ce genre
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
....
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
....
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 :
Les fonctions :
:'(
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.
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.
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 ...
Pas d'autres suggestions Messieurs ? :-)
Par contre je peux peut être m'en inspirer pour ce que je veux faire ... Je verrais.