Précédent   Forum des professionnels en informatique > PHP > Langage > Regex
Regex Forum d'entraide sur les expressions rationnelles PHP. Avant de poster -> FAQ regex, Cours de regex et Sources de regex
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 23/03/2011, 12h07   #1
Invité de passage
 
Inscription : octobre 2007
Messages : 6
Détails du profil
Informations forums :
Inscription : octobre 2007
Messages : 6
Points : 0
Points : 0
Par défaut RegExp: recherche type contient dans chaine taille fixe

Bonjour,
je cherche a faire une reg exp permettant de chercher dans une chaine composée de plusieurs zones de taille fixe dont la longueur et la position sont connues, une ou plusieurs valeurs.

La / Les valeur fournit n'est pas forcément complète, on fait donc une recherche de type contient dans chaque zone.

Exemples de chaine à analyser:
0123456789DurandxxxxxxxxxxxxxxJeanxxxxxxxxxxxxxxxx01234567890123456789012345
OU
0123456789xxxxxxDurandxxxxxxxxxxxxJeanxxxxxxxxxxxx01234567890123456789012345
OU
0123456789xxxxxxxxxxxxxxDurandxxxxxxxxxxxxxxxxJean01234567890123456789012345
...


La zone contenant le nom est sur 20 caractères et commence à la position 11.
La zone contenant le prénom est sur 20 caractères et commence à la position 31.

Si on cherche une seule des 2 zones, par exemple le prénom. Je génère cette expression:
.{30}.{0,16}Jean
On se place à la position 31 et on fait un match si l'expression contient 0 à 16 caractères quelconque suivi du prénom Jean.
Pas de problème avec cette expression. Ca permet de trouver la valeur Jean n'importe où dans la zone.

Maintenant, si je dois chercher nom et prénom, l'expression générée est:
(.){10}.{0,14}Durand.{0,16}Jean
or dans la 1ere ligne d'exemple, Durand n'est pas préfixé par des espaces mais suffixé. On trouve donc le nom directement, préfixé par 0 espace.
La reg exp ne match pas car on cherche le prénom au mauvais endroit.

J'ai eu plusieurs piste pour solutionner ce problème mais pour l'instant, je n'ai pas trouvé de solution qui fonctionne dans tous les cas.

Pour info, la reg exp sera générée par code.

J'espère que l'un d'entre vous pourra m'aider.
arc59 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/03/2011, 12h24   #2
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 984
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 2 984
Points : 5 014
Points : 5 014
Une regexp de cette forme devrait permettre d'extraire les deux données qui t'intéressent de la chaine:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
 
$p = "#(?<nom>[[:alpha:]]+)[[:space:]]*(?<prenom>[[:alpha:]]+)#";
 
$t = array(
"0123456789Durand             Jean                01234567890123456789012345",
"0123456789      Durand           Jean            01234567890123456789012345",
"0123456789             Durand                    Jean01234567890123456789012345",
);
 
foreach ($t as $s) {
  preg_match($p, $s, $m);
  var_dump($m);
}
Affiche:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
array
  0 => string 'Durand             Jean' (length=23)
  'nom' => string 'Durand' (length=6)
  1 => string 'Durand' (length=6)
  'prenom' => string 'Jean' (length=4)
  2 => string 'Jean' (length=4)
 
array
  0 => string 'Durand           Jean' (length=21)
  'nom' => string 'Durand' (length=6)
  1 => string 'Durand' (length=6)
  'prenom' => string 'Jean' (length=4)
  2 => string 'Jean' (length=4)
 
array
  0 => string 'Durand                    Jean' (length=30)
  'nom' => string 'Durand' (length=6)
  1 => string 'Durand' (length=6)
  'prenom' => string 'Jean' (length=4)
  2 => string 'Jean' (length=4)
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/03/2011, 13h53   #3
Modérateur
 
Avatar de Nesmontou
 
Homme Benjamin PREVOT
Architecte de système d'information
Inscription : septembre 2004
Messages : 1 568
Détails du profil
Informations personnelles :
Nom : Homme Benjamin PREVOT
Âge : 30
Localisation : France, Nord (Nord Pas de Calais)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : Finance

Informations forums :
Inscription : septembre 2004
Messages : 1 568
Points : 2 493
Points : 2 493
Bonjour,

Puisque tu connais la longueur du champ et sa position, pourquoi ne pas utiliser les fonctions substr et strpos plutôt que les expressions régulières ?
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
function recherche($chaine, $cherche, $debut, $longueur)
{
	$chaine = substr($chaine, $debut, $longueur);
 
	return ( strpos($chaine, $cherche) !== false );
}
 
function rechercheNom($chaine, $prenom)
{
	return recherche($chaine, $prenom, 10, 20);
}
 
function recherchePrenom($chaine, $prenom)
{
	return recherche($chaine, $prenom, 30, 20);
}
 
$chaine1 = '0123456789Durand              Jean                01234567890123456789012345';
$chaine2 = '0123456789      Durand            Jean            01234567890123456789012345';
$chaine3 = '0123456789              Durand                Jean01234567890123456789012345';
 
var_dump(recherchePrenom($chaine1, 'Durand'));
?>
S'il ne faut pas tenir compte de la casse, utilise alors la fonction stripos.

Bon développement
__________________
Si vous ne pouvez expliquer un concept à un enfant de six ans, c'est que vous ne le comprenez pas complètement. Albert EINSTEIN

F.A.Q. : Java, PHP, (X)HTML / CSS

N'oubliez pas de cliquer sur le bouton Résolu en bas de page quand vous avez obtenu une solution à votre problème
Nesmontou est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/03/2011, 17h35   #4
Invité de passage
 
Inscription : octobre 2007
Messages : 6
Détails du profil
Informations forums :
Inscription : octobre 2007
Messages : 6
Points : 0
Points : 0
Merci pour ces réponses.

@Benjamin Delespierre
Ton expression est correcte pour l'exemple que je donne mais dans la majorité des cas rééls de mon application, les 2 zones ne se suivent pas.
Voici un autre exemple plus réaliste:

Citation:
XXXXXXXXXXXXXXXXXXXXxxxxDurandxxxxxxxxxxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXJeanxxxxxxxxxxxxxxxxXXXXXXXXXXXXXXXX
ou X représente le contenu d'autres zones dans mon fichier
et x représente le contenu des zones de recherche qui ne correspondent pas à la valeur recherchée (exemple pour le prénom, si on cherche Jean et qu'on a Jean Michel dans la zone, on doit quand même afficher le résultat.

@Nesmontou
En fait, en début de conception, la question s'est posée mais on a choisi de travailler avec les expressions régulières car:
- elles sont faites pour faire des recherches optimisées sur du texte
- elles permettaient d'industrialiser en grande partie le code, en créant une fabrique de reg exp en fonction des critères de recherche (et donc de limiter la taille du code => le temps)

On a réussi à gérer tous nos cas via les reg exp, y compris un cas de recherche d'absence de données (en gros, la reg exp match le complément de ce qui a été trouvé. Ex simpliste: on cherche toutes les personnes dont le prénom n'est pas Pierre.).

Reste ce dernier cas imparfait que nous gérons avec l'expression ci dessous.
On va poser les bases suivantes:
La zone nom se trouve en position 31 à partir du début de ligne et fait 20 caracteres.
La zone prénom se trouve en position 59 (59-31 = 28) à partir du début de ligne et fait 20 caracteres.
Si on cherche Durand (6 caracteres) Jean (4 caractères)
L'expression générée par notre appli est:
Citation:
^(.){30}(.){0,14}Durand(.){22,36}Jean(.)+$
^(.){30}: permet de se placer en position 31 à partir du début de ligne
(.){0,14}Durand: permet de chercher parmis les 20 caracteres de la zone la valeur Durand
(.){22,38}Jean: permet de chercher à partir de la position 59 (31+6+22) à 75 (31+6+38) la valeur Jean
(.)+$: ramene le reste de la ligne.

Concrètement, cela fonctionne mais si dans la zone nom on a comme valeur "Durand Jean " et dans la zone prénom on a "Michel ", la reg exp matchera, ce qui ne devrait pas être le cas.

Je n'arrive pas à trouver l'astuce qui me permettrait de matcher uniquement quand on a les 2 valeurs recherchées précisément dans leur zone.
arc59 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/03/2011, 22h03   #5
Modérateur
 
Avatar de Nesmontou
 
Homme Benjamin PREVOT
Architecte de système d'information
Inscription : septembre 2004
Messages : 1 568
Détails du profil
Informations personnelles :
Nom : Homme Benjamin PREVOT
Âge : 30
Localisation : France, Nord (Nord Pas de Calais)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : Finance

Informations forums :
Inscription : septembre 2004
Messages : 1 568
Points : 2 493
Points : 2 493
Bonsoir,
  • Citation:
    Envoyé par arc59
    elles sont faites pour faire des recherches optimisées sur du texte
    Je dirais pas toujours : http://fr2.php.net/manual/fr/function.preg-match.php
    Citation:
    Envoyé par php.net
    N'utilisez pas preg_match() si vous voulez uniquement savoir si une chaîne est contenue dans une autre. Utilisez dans ce cas les fonctions strpos() ou strstr(), qui sont beaucoup plus rapides.
  • Citation:
    Envoyé par arc59
    et donc de limiter la taille du code => le temps
    Peu de code ne veut pas dire temps de traitement amélioré (cf. ci-dessus).

Sinon, je ne comprends l'avantage de générer des expressions régulières (temps de calcul de la regex...) par rapport à la méthode que je t'indiquais
__________________
Si vous ne pouvez expliquer un concept à un enfant de six ans, c'est que vous ne le comprenez pas complètement. Albert EINSTEIN

F.A.Q. : Java, PHP, (X)HTML / CSS

N'oubliez pas de cliquer sur le bouton Résolu en bas de page quand vous avez obtenu une solution à votre problème
Nesmontou est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/03/2011, 09h38   #6
Invité de passage
 
Inscription : octobre 2007
Messages : 6
Détails du profil
Informations forums :
Inscription : octobre 2007
Messages : 6
Points : 0
Points : 0
Citation:
Peu de code ne veut pas dire temps de traitement amélioré (cf. ci-dessus).
Je suis évidemment d'accord, ce que je disais, c'est que le volume de code à produire est moins important, les cas géré étant assez standardisé. Ce qui permet également d'avoir un code plus fiable, car moins de cas possible.

Avez vous des pistes de résolution à me proposer ?
arc59 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/03/2011, 10h48   #7
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 984
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 2 984
Points : 5 014
Points : 5 014
Citation:
elles sont faites pour faire des recherches optimisées sur du texte
Oui, dans la mesure ou la recherche à faire est complexe. strpos ou substr sont toujours plus rapides que la plus optimale des expressions régulières. S'il ne s'agit que de vérifier la présence de deux éléments dans une chaine, il vaut mieux faire 2x strpos qu'une regexp.

Citation:
elles permettaient d'industrialiser en grande partie le code, en créant une fabrique de reg exp en fonction des critères de recherche (et donc de limiter la taille du code => le temps)
La généricité n'est pas un facteur de gain de temps, au contraire.

D'ici, je pense que la regexp "^(.){30}(.){0,14}Durand(.){22,36}Jean(.)+$" peut être réduite à: "Durand.*Jean" tout simplement.
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/03/2011, 15h09   #8
Invité de passage
 
Inscription : octobre 2007
Messages : 6
Détails du profil
Informations forums :
Inscription : octobre 2007
Messages : 6
Points : 0
Points : 0
Par défaut la regexp solution

On m'a donné la solution sur un autre forum:
Code :
1
2
 
^(.{15}(?=.{0,14}Durand).{20}.{135}(?=.{0,16}Jean).{20})$
La partie (?=.{0,14}Durand) est non capturante et conditionne la capture .{20}. Si on trouve durand n'importe où dans la zone, alors on capture les 20 caractères de la zone.
arc59 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 21h37.


 
 
 
 
Partenaires

Hébergement Web