Je vois le cour de gbdiver sur le c++ moderne et j'en suis aux expressions régulières.
Je croyais avoir bien compris le principe jusqu'à ce que je tombe sur cet exemple qui me laisse comme un c.. , si je peux me permettre
{
std::regex pattern("([a-zA-Z]+) \\1");
std::string replacement = "$1";
std::string target = "The cat cat bites the dog dog.";
std::string output_str = regex_replace(target, pattern, replacement);
std::cout << output_str << std::endl;
}
Ce qu'il affiche est " The cat bites the dog."
Par quel miracle saute-t-il les mots doublés?
Il prend chaque lettre si il y en a 1 ou + si j'ai bien compris. Mais quand s’arrête le groupe de capture, quand est-ce qu'il recommence, d’où viennent les espaces...
Je suis perdu.
- Edité par lio2609 21 novembre 2017 à 12:42:50
" Ce n'est pas parce qu'ils sont beaucoup à avoir tort qu'ils ont raison . "
En réalité il ne saute pas les mots doublés, mais captures 2 mots identiques qui se suivent.
(...) permet de capture quelque chose et \\1 correspond à la capture numéro 1.
En gros, la regex dit: on prend un mot, un espace et le même mot que précédemment. Le tout sera remplacé par $1 qui correspond à la capture 1 dans la fonction de remplacement. Résultat, regex_replace prend 2 mots identiques et le remplace par le premier (donc supprime le second).
Note qu'avec format_sed, on pourrait avoir \\1 pour la capture et le remplacement.
En réalité, tous les doublons ne sont pas supprimés puisque que la regex fonctionne par paire.
dog dog -> dog
dog dog dog -> dog dog
dog dog dog dog -> dog dog
dog dog dog dog dog -> dog dog dog
Pour véritablement supprimer les séquences de mots identiques:
J'ai maintenant compris le principe mais je ne comprends toujours pas comment la syntaxe de cette regex le produit.
"[a-zA-Z]" : n'importe quelle lettre min ou maj ( ne vaut que pour une seule lettre ? )
"([a-zA-Z]+)" : n'importe quelle lettre min ou maj si il en existe 1 ou plus et on prend tout ça en capture ? ( on s’arrête aux espace ? Si non on va jusqu'au bout de la phrase ?! )
"\\1" : sert a dire que ce qu'il y a entre parenthèse peut être rappeler par "$1" ? ( donc toute la phrase ? Sinon pourquoi "cat" puis "dog" ?)
" Ce n'est pas parce qu'ils sont beaucoup à avoir tort qu'ils ont raison . "
> "[a-zA-Z]" : n'importe quelle lettre min ou maj ( ne vaut que pour une seule lettre ? )
Oui
"([a-zA-Z]+)" : n'importe quelle lettre min ou maj si il en existe 1 ou plus et on prend tout ça en capture ? (
Oui
> on s’arrête aux espace ? Si non on va jusqu'au bout de la phrase ?! )
On s'arrête quand il n'y plus de correspondance. Donc, quand différent de lettre min ou maj.
Mais regex_replace fait une boucle jusqu'à ne plus pouvoir rien remplacer.
Si à partir d'un caractère la regex ne correspond a rien, alors on passe au caractère suivant
Si à partir d'un caractère la regex correspond à quelque chose, alors on fait un remplacement et on continue la recherche depuis la fin de la correspondance.
> "\1" : sert a dire que ce qu'il y a entre parenthèse peut être rappeler par "$1" ?
Non. Ce sont 2 choses différentes qui font référence à une capture (ce qu'il y a entre parenthèse).
\1 dans la regex indique que le pattern doit ajouter "dynamiquement" un morceau de texte dans la recherche, celui présent dans la capture 1.
$1 dans le texte de remplacement s'applique après que le passage de la regex pour remplacer la correspondance de la regex (càd mot, espace, le même mot) par la capture 1 (càd. mot).
Merci beaucoup pour le temps passé à me répondre, mais je suis un lent, ça risque donc d'être long
Donc, dans ce cas ci :
A quel moment la regex dit qu'elle prend [un mot, un espace puis un mot] ?
Moi je vois ( on est bien d'accord que je vois flou ) :
"([a-zA-Z]+)" Je prends le premier mot puisqu'il n'y a plus de correspondance avec l'espace , je le copie dans output_str , je recommence avec le mot suivant etc etc .
Ce qui rendrait la même phrase sans les espaces... Ce qui n'est manifestement pas le cas...
Je nage.
" Ce n'est pas parce qu'ils sont beaucoup à avoir tort qu'ils ont raison . "
> A quel moment la regex dit qu'elle prend [un mot, un espace puis un mot] ? Moi je vois "([a-zA-Z]+)"
Il faut prendre la regex dans son ensemble: "([a-zA-Z]+) \\1".
Je te montre un exemple étape par étape du fonctionnement de regex_replace
v: position de début de correspondance
^: position du curseur de recherche en cours
out: chaîne de résultat
v
a b b c
^
out = ""
état = "([a-zA-Z]+)"
L'"état" trouve des caractères, on avance le curseur de recherche.
La capture 1 contient a.
v
a b b c
^
out = ""
état = " "
Espace trouvé, on avance
v
a b b c
^
out = ""
Échec de la correspondance, on est sur b on attend a.
On déplace le caractère de début de correspondance dans out puis on reprend avec le caractère suivant.
v
a b b c
^
out = "a"
état = "([a-zA-Z]+)"
" " ne correspond pas, on fait pareil qu'à l'étape précédente.
v
a b b c
^
out = "a "
état = "([a-zA-Z]+)"
On trouve un mot (b, \1 correspond maintenant à b)
v
a b b c
^
out = "a "
état = " "
espace trouvé, on avance le curseur de recherche
v
a b b c
^
out = "a "
état = " "
On trouve b qui correspond à \1. La regex est "complète", on fait un remplacement de "b b" par "$1" qui correspond à la capture 1 est donc á "b"
Si on transpose ça à notre phrase , ca veut dire que "([a-zA-Z]+)" met toute une série de lettres dans la capture 1 jusqu'à ce qu'elle tombe sur autre chose qu'une lettre ( dans notre cas un espace).
Puis compare la prochaine suite de lettres ( capture 2 ? ) avec capture 1 :
Si != elle envoi la capture 1 dans out et reprend le test à la capture 2 (qui devient donc la 1) etc
Si == elle envoi la capture 1 dans out et reprend le test après la capture 2.
C'est bien ça?
" Ce n'est pas parce qu'ils sont beaucoup à avoir tort qu'ils ont raison . "
> Si on transpose ça à notre phrase , ca veut dire que "([a-zA-Z]+)" met toute une série de lettres dans la capture 1 jusqu'à ce qu'elle tombe sur autre chose qu'une lettre ( dans notre cas un espace).
Oui
> Puis compare la prochaine suite de lettres ( capture 2 ? ) avec capture 1 :
Les captures 1 à n font uniquement référence aux parenthèses. Une paire de parenthèse = une capture.
Il y a aussi la capture 0 qui fait référence au texte complet qui correspond à la regex. C'est la partie qui va être remplacé par regex_replace.
> Si != elle envoi la capture 1 dans out et reprend le test à la capture 2 (qui devient donc la 1) etc
Pas tout à fait. On ne peut pas sauter un groupe de lettre est dire « on a trouvé abcd dans abcd ef, mais le reste ne correspond pas alors on reprend depuis l'espace. » Parce qu'avec une regex un peu plus complexe bcd ef peut avoir une correspondance (ex: ([a-z]+) \\1|bcd). Du coup, quel que soit le nombre de caractère traversé avant un échec, on avance toujours de 1 seul caractère.
Ceci explique pourquoi "abc bc" est remplacé par "abc". abc ne fonctionne pas, mais bc si.
- Edité par jo_link_noir 23 novembre 2017 à 22:59:04
Il va me falloir beaucoup d'exercices pour assimiler ça mais je crois que j'ai compris, grâce à toi.
" Ce n'est pas parce qu'ils sont beaucoup à avoir tort qu'ils ont raison . "
Expressions régulières
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.