Split chaine selon conditions...

Résolu
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 - 24 févr. 2009 à 10:17
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 - 25 févr. 2009 à 14:17
Bonjour à tous,

Je suis sur un petit moteur de recherche sur une base Postgres en C#. j'ai quelques difficultés pour un Split avec des conditions.

J'ai une requéte SQL comme suis :

Select * FROM base WHERE ( condition 1) AND  (Condition 2)

Condition 1 me permettant de filtré les resultats suivant des conditions particuliére [ langue / type de fichier etc ]
Condition 2 étant la recherche par mots clefs.

Donc voici mon code actuellement pour la construction de ma Condition 2

string[] mots = chainerecherche.Split(' ');
bool start = true;

foreach (string mot in mots)

            if (start == true)
            {
              requete += " ( LOWER(champ1) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' OR LOWER(champ2) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' OR LOWER(champ3) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' )";
                start = false;
            }
            else
            {
                requete += " OR ( LOWER(champ1) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' OR LOWER(champ2) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' OR LOWER(champ3) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' )";
            }
           
        }

        requete += ")";

Donc je cherche une petite piste pour des cas particulier :
La recherche porte sur une chaine entiére est le format de ma chaine d'entrée est  de type : mot0 "mot1 mot2" mot3
donc je voudrais spliter ma chaine pour avoir dans mon tableau
mot[0] = mot0
mot[1] = "mot1 mot2"
mot[2] = "mot3"

Sachant que en plus le format de la chaine n'est pas forcément celui ci est peut trés bien avoir 1, aucun ou plusieurs mots avant ou aprés, et qu'il peut trés bien y avoir 2 chaine entre " " ... ou même aucun " " [ mais la c'est pas un probléme ]

Il y as des choses inutiles [ comme le trim() ] les accent ne sont pas gérés mais c'est pas trop grave pour le moment ...

J'ai quelques idées sur comment "Néttoyer" ma chaine mais chaque fois c'est peut ou pas concluant, si quelqu'un avais une petite piste ;)

Merci et bonne journée
A voir également:

10 réponses

cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 févr. 2009 à 17:21
Oula non ça marche pas comme ça...
Regex.Split est beaucoup plus puissant qu'un simple Split

Tu peux par exemple faire qqch comme ça:

string txt =
@"""mot1 mot2"" mot3 mot4 ""mot5 mot6""";

string[] res =
Regex.Split(txt,
@"""(.+?)""|\s+",
RegexOptions.Compiled);

Ca donne pas tout à fait le bon résultat, y'a des strings vides en trop, mais c'est une bonne piste.

Je te laisses continuer dans cette direction...

<hr />
-Blog-
-Site Perso-
3
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
25 févr. 2009 à 13:35
Attention aux performances...
Les regex c'est bien sur des gros textes quand on doit faire des opérations assez complexes (ca évite de se casser la tête à faires plusieurs boucles qui s'imbriquent les unes dans les autres, etc) mais c'est pas très rapide. Regex.Compile permet de compiler l'expression, ce qui donne une exécution plus rapide, mais pour de petit texte, le temps de compilation peut être supérieur au temps d'exécution!

Donc de faire une regex qui fait tout le travail, avec éventuellement un Regex.Compile peut-être une bonne idée.
Faire des regex sur des petits textes et de plus dans une boucle, me paraît nettement moins judieux (et c'est ce que tu sembles faire).

A voir...

<hr />
-Blog-
-Site Perso-
3
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 févr. 2009 à 12:41
Hello,
Regarde du côté de Regex.Split, ça devrait faire l'affaire...

<hr />
-Blog-
-Site Perso-
0
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 2
24 févr. 2009 à 15:00
En fait cela ne fait que 50% du boulot ...
sur une chaine type : "mot1 mot2" mot3 mot4 "mot 5 mot6"

Je récupère 3 chaines :
"mot1 mot2" - "mot3 mot4" - "mot5 mot6"
au lieu de 4 chaines :
"mot1 mot2" - "mot3" - "mot4" - "mot5 mot6"

Cela reviens à chaine.Split(' " '); que j'ai déjà essayer... ( d'ailleurs un Regex.Split aurais était plus judicieux )
Donc je pensais le faire en 3 étapes :

1 -> Splité sur les " pour avoir mes chaines
2 -> Controler et enlever les chaines entre " "
3 -> Splité le reste avec les espace ...

Seulement dans mon cas la sortie "mot3 mot4" existe dans ma chaine de référence ...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 2
24 févr. 2009 à 17:40
J'avais bien remarqué que le Regex était bien plus puissant qu'un simple Split, mais mes essais était pas concluant ...
Maintenant tout est ok, je trouve bien toutes mes chaines comme je devrais les trouvées.

Il faudra que je me penche un peut sur l'utilisation du @ ... j'ai pas fait un seul essai avec ...

En tout cas merci :D

Bonne soirée.
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 févr. 2009 à 18:59
Tu as réussi avec une Regex?
Si oui, ça serait sympa de la partager sur le forum :)

<hr />
-Blog-
-Site Perso-
0
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 2
25 févr. 2009 à 09:20
Bonjour,

Comme tu le disais il reste des string vides, il as fallut que je fasse un petit contrôle pour les éliminés et pas faire de recherches sur le vide. De la même manières, et dans l'optique "un utilisateur fait toujours n'importe quoi" j'ai prévue le cas ou une chaine type : "mot1""""mot2" serais saisies. et donc éliminé les chaines parasites.
Pour le moment il n'y as pas de gestion des accents, ni des caractères spéciaux.

Voila pour le code tel qu'il est actuellement.

string text = @chainerecherche;
string pattern = @"""(.+?)""|\s+";
string[] mots = Regex.Split(text,pattern,RegexOptions.Compiled);
       
bool start = true;

requete += "(";
foreach (string mot in mots)
{
    if (mot.Trim() != "" && mot.Replace('"',' ').Trim() != "")
   {
       if (start == true)
      {
          requete += " ( LOWER(champ1) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' )";
          start = false;
       }
       else
      {
         requete += " OR ( LOWER(champ1) LIKE '%" + mot.Trim().ToLowerInvariant() + "%' )";
       }
   }
}

requete += ")";
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
25 févr. 2009 à 11:36
Le tout doit pouvoir être fait en une ligne, avec la bonne regex...
Encore faut-il la trouver. Comme je ne suis pas un expert dans ce domaine, je ne vais pas essayer car je risque de perdre quelques heures :D

<hr />
-Blog-
-Site Perso-
0
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 2
25 févr. 2009 à 11:43
Bon voici la version "finie" mais peut être pas optimale.
Il faudrait que j'en fasse une fonction qui retourne un tableau de string prés a l'emploi ça serrais plus efficace, et surtout utilisable sans modification.

Pour la procédure :
J'élimine d'abord la ponctuation en la remplaçant par un espace, mais sans toucher aux " qui me servent a délimiter mes chaines de recherche complètes. On pourrais éliminé plus de caractère, mais j'ai besoin pour le moment de certain de ses caractères pour des recherches sur dates ou formules mathématiques ...
Ensuite, je récupère chacune de mes chaines.
Pour chaque chaine je met un _ (caractère joker pour la requête SQL  ) à la place des accents
Ensuite je vérifie que je n'est ni de chaine vide, ni de chaine uniquement composer de ", ni de chaine composer que d'un _ [ pour éviter qu'un champ joker s'applique et donc retourne la totalité de la base ]

Si quelqu'un vois des amélioration pour les cas que auquels je n'aurais pas pensés ;)

string text = @chainerecherche;
string pattern = @"""(.+?)""|\s+";
string patternacc = @"[àâäéèêëïïöôùüû]";
string patternspe = @"[!?,;._]";
text = Regex.Replace(text,patternspe,"", RegexOptions.Compiled);
string[] mots = Regex.Split(text,pattern,RegexOptions.Compiled);

requete += "(";
foreach (string mot in mots)
{
   string motnettoyer = mot;
   motnettoyer = Regex.Replace(motnettoyer, patternacc, "_", RegexOptions.Compiled);    if (motnettoyer.Trim() !"" && mot nettoyer <gras>.Replace('"',' ').Trim() ! "" && mot</gras>nettoyer != "_")
   {
       if (start == true)
      {
          requete += " ( LOWER(champ1) LIKE '%" + mot nettoyer .Trim().ToLowerInvariant() + "%' )";
          start = false;
       }
       else
      {
         requete += " OR ( LOWER(champ1) LIKE '%" + mot nettoyer .Trim().ToLowerInvariant() + "%' )";
       }
   }
}

requete + = ")";
0
Lyle56 Messages postés 240 Date d'inscription jeudi 1 mai 2008 Statut Membre Dernière intervention 19 juillet 2012 2
25 févr. 2009 à 14:17
Heu non, en fait la boucle me permet simplement de construire une requête SQL ...
La je ne sais pas quel est la taille de mon texte a la base, cela peut être un seul mot, ou une phrase complète ...
Je ne sais pas non plus quel est le format exact du texte, même si une structure générale se dégage [ chaine entre " ou non ]

Pour le Regex qui se trouve dans la boucle,  je pourrais aussi bien utilisé un String.Replace, mais la aussi je ne sais pas exactement combien d'accent se trouve dans la chaine, ni même si la chaine est juste composé de un seul mot ou de plusieurs.
0
Rejoignez-nous