pb expression réguliére [PHP] - PHP - Programmation
Marsh Posté le 30-03-2005 à 23:30:27
Ta contrainte n'est pas informatique mais lexicale: il s'agit de distinguer le point final (de phrase, je suppose) du point abréviatif. Or, il y a de nombreuses situations où un point abréviatif peut apparaître sans clôturer la phrase: J.-M. Martin, mais aussi etc. ou par ex., ou bien encore dans un emploi énumératif (1. item1, 2. item2...)
Bref, avec une simple regexp, tu pourras au mieux fixer une contrainte arbitraire sur la TAILLE MINIMALE d'une phrase.
1) Pour capturer les points de suspensions, pas de difficulté, il s'agit d'ajouter un + derrière le schéma.
2) Pour imposer une taille mini avant le point, il sera préférable d'utiliser preg_replace avec l'option /e afin d'opérer un traitement conditionnel.
Typiquement, tu peux décréter que des termes de moins de trois caractères entre deux points ne constituent pas une phrase.
Ca donne un code du genre:
// Séparation par BR seulement si + de 2 cars avant le pt
$chaine = preg_replace("/([^.]*)\.+/e", '(strlen("$1" )>2)?"$0<br \><br \>":"$0"', $chaine);
Marsh Posté le 31-03-2005 à 09:51:38
Merci ça marche
voici ce que j'ai compris, peux tu me dire si c'est correct.
$chaine = preg_replace("/([^.]*)\.+/e", '(strlen("$1" )>2)?"$0<br \><br \>":"$0"', $chaine);
1ere partie
/.........../e : option sur se qu'il y a entre les /
([^.]*) : ce qui commence par 0, 1 ou plusieurs points
\.+ : \ pour caractère . et le + dir qu'il apparait une ou plusieurs fois
2eme partie
(strlen("$1" )>2)? : on prend longueur de la chaine $1 > à 2 apparait 0 ou 1 fois
"$0<br \><br \>":"$0" je n'ai pas compris les : et à quoi sert le $0 aprés les :
Le $1 et le $0 corresponde à quoi?
Marsh Posté le 31-03-2005 à 13:18:18
rdams a écrit : Merci ça marche |
Hou la, rdams!, tu fais quelques fausses interprétations dans l'analyse de mon code. Lis absolument la doc de preg_replace!
Reprenons rapidement le scénario:
$chaine = preg_replace("/([^.]*)\.+/e", '(strlen("$1" )>2)?"$0<br \><br \>":"$0"', $chaine);
1) le pattern /([^.]*)\.+/
------------------------------------
a) [^.]* capture la plus longue suite possible -- éventuellement vide -- de caractères autres que le point!
C'est une classe de caractères (syntaxe [...]), le ^ signifie ici l'exclusion (c'est une sorte de NON logique) et pas le début d'une chaîne. Souviens toi que selon le contexte où ils apparaissent, les opérateurs de regexp n'ont pas du tout la même sémantique. Au passage, note que le point n'a pas besoin d'être échappé en \. dans la classe de car.
b) Les parenthèses ([^.]*) autour de la classe sont dites "capturantes", càd que preg_replace va stocker le contenu en direct-live dans une sorte de variable, à laquelle on accédera par $1 (car c'est la 1ère parenthèse capturante). Note que la pseudo-variable $0 désigne toujours, parenthèses ou pas, l'intégralité de la capture. Ainsi, $1 correspondra, dans chaque schéma $0 capturé par la regexp, la partie correspondant à la séquence de caractères "non-points" située avant le(s) point(s). C'est sur cette partie que l'on fera peser la condition de longueur mini.
c) Pour la suite du pattern, \.+, ton interprétation est OK: on capture la plus longue suite de points sachant qu'il en faut au moins un. Les points de suspension sont donc attrapés aussi.
2) le remplacement conditionnel
------------------------------------
a) L'option e à la fin du pattern indique, c'est un aspect capital, que le 2e argument de preg_replace doit être considéré, non pas comme une simple chaine de remplacement, mais comme du code PHP (fourni dans une chaine!) à interpréter à la volée, lequel va générer la chaine effective du remplacement...
b) Le code en question est donc fourni par la chaîne:
'(strlen("$1" )>2)?"$0<br \><br \>":"$0"'
preg_replace va donc charger en guise de chaîne de remplacement le résultat du code:
(strlen("$1" )>2) ? "$0<br \><br \>" : "$0"
qui n'est pas autre chose qu'une affectation conditionnelle:
(condition) ? valeur_si_oui : valeur_si_non
- La condition (strlen("$1" )>2) pèse sur la fameuse pseudo-variable $1 capturée plus haut. Elle impose que la chaine des non-points soit au moins de longueur 3.
- Si la condition est vérifiée, le code renvoie "$0<br \><br \>", càd l'ensemble de la capture suivie de ton séparateur <br /><br /> : on est dans le cas où le(s) point(s) détectés sont considérés comme finaux.
- Si la condition n'est pas vérifiée, le code renvoie bêtement "$0", càd la chaine capturée elle-même, ce qui revient à dire qu'on ne change rien à cet endroit-là (du fait que $1 est trop court): c'est ainsi que les abréviations du type "J. M." ne seront pas coupées.
NOTA BENE: Comme je te l'ai dit, le code que je t'ai donné n'est qu'un début de solution à ton problème. Tu seras probablement confronté à des contextes ambigus où le point abréviatif serait aussi un point final. Il suffit par exemple que "J. M." soit le dernier mot de la phrase! Pour traiter tous les cas de figure, il faudrait connaître mieux les conditions "linguistiques" de ton programme.
Marsh Posté le 01-04-2005 à 09:09:17
pour le [^.]* j'aurais du faire plus attention. je l'avais déjà rencontré.
j'ai quand même un petit problème :
si j'ai J.M. Martin. où Martin point et la fin de la phrase, ça passe à la ligne comme ceci
J.
M. Martin
que je mette un espace ou non entre le J. et le M.
Connais tu un site où je pourrais trouver des cours sur les expressions régulières et des exercices?
Merci
Marsh Posté le 30-03-2005 à 21:52:11
Bonjour,
J'ai une chaine de caractère et je veux passer à la ligne à chaque '.'
J'utilise donc
$chaine = ereg_replace("\.",".<br><br>",$chaine);
le proble c'est lorsque j'ai '...' ou des initiale 'J.M. Martin.'
Pour les '...' je rajoute cette ligne de code
$chaine = ereg_replace("\.<br><br>\.<br><br>\.<br><br>","...",$chaine);
mais je ne vois pas comment faire pour aller à la ligne juste aprés Martin et pas à chaque initiale.
Merci