JavaRush /Blog Java /Random-FR /RegEx : 20 petites étapes pour maîtriser les expressions ...
Artur
Niveau 40
Tallinn

RegEx : 20 petites étapes pour maîtriser les expressions régulières. Partie 4

Publié dans le groupe Random-FR
RegEx : 20 petites étapes pour maîtriser les expressions régulières. Partie 1 RegEx : 20 courtes étapes pour maîtriser les expressions régulières. Partie 2 20 petites étapes pour maîtriser les expressions régulières. Partie 3 Cette dernière partie, au milieu, abordera des éléments principalement utilisés par les maîtres des expressions régulières. Mais le matériel des parties précédentes était facile pour vous, n'est-ce pas ? Cela signifie que vous pouvez manipuler ce matériau avec la même facilité ! Original ici RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 - 1 <h2>Étape 16 : regrouper sans capturer (?:)</h2> RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 - 2Dans les deux exemples de l'étape précédente, nous capturions du texte dont nous n'avions pas vraiment besoin. Dans la tâche Tailles de fichiers, nous avons capturé les espaces avant le premier chiffre de la taille des fichiers, et dans la tâche CSV, nous avons capturé les virgules entre chaque jeton. Nous n'avons pas besoin de capturer ces caractères, mais nous devons les utiliser pour structurer notre expression régulière. Ce sont des options idéales pour utiliser un groupe sans capturer (?:). Un groupe sans capture fait exactement ce à quoi il ressemble : il permet de regrouper et d'utiliser des caractères dans des expressions régulières, mais ne les capture pas dans un groupe numéroté :
pattern: (?:")([^"]+)(?:") 
string: Je veux seulement "le texte entre ces guillemets" .
correspondances :             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
groupe :                 1111111111111111111111111111    
( Exemple ) L'expression régulière correspond désormais au texte cité ainsi qu'aux guillemets eux-mêmes, mais le groupe de capture n'a capturé que le texte cité. Pourquoi devrions-nous faire cela ? Le fait est que la plupart des moteurs d'expressions régulières vous permettent de récupérer le texte des groupes de capture définis dans vos expressions régulières. Si nous pouvons supprimer les caractères supplémentaires dont nous n'avons pas besoin sans les inclure dans nos groupes de capture, cela facilitera l'analyse et la manipulation du texte ultérieurement. Voici comment nettoyer l'analyseur CSV de l'étape précédente :
motif : (?:^|,)\s*(?:\"([^",]*)\"|([^", ]*)) 
chaîne :   a , " b ", " cd ", e , f , " gh ", dfgi ,, k , "", l 
correspond à : ^ ^ ^^^ ^ ^ ^^^ ^^^^ ^ ^ 
groupe :    2 1 111 2 2 111 2222 2 2    
( Exemple ) Il y a quelques choses à <mark>remarquer ici :</mark> Premièrement, nous ne capturons plus les virgules depuis que nous avons changé le groupe de capture (^|,)en un groupe de non-capture (?:^|,). Deuxièmement, nous avons imbriqué le groupe de capture dans le groupe de non-capture. Ceci est utile lorsque, par exemple, vous avez besoin qu’un groupe de caractères apparaisse dans un ordre spécifique, mais que vous ne vous souciez que d’un sous-ensemble de ces caractères. Dans notre cas, nous avions besoin de caractères autres que les guillemets et les virgules [^",]*pour apparaître entre guillemets, mais nous n'avions pas réellement besoin des caractères de guillemets eux-mêmes, ils n'avaient donc pas besoin d'être capturés. Enfin, <mark>notez</mark> que dans l'exemple ci-dessus, il existe également une correspondance de longueur nulle entre les caractères ket l. Les guillemets ""sont la sous-chaîne recherchée, mais il n'y a aucun caractère entre les guillemets, donc la sous-chaîne correspondante ne contient aucun caractère (longueur nulle). <h3>On doit consolider nos connaissances ? Voici deux tâches et demie qui nous aideront :</h3> À l'aide de groupes non capturants (et de groupes capturants, de classes de caractères, etc.), écrivez une expression régulière qui capture uniquement les tailles de fichiers correctement formatées sur la ligne. ci-dessous :
modèle:
chaîne :   6,6 Ko 1..3 Ko 12 Ko 5G 3,3 Mo Ko .6,2 To 9 Mo .
correspondances : ^^^^^ ^^^^^ ^^^^^^ ^^^^ 
groupe :    11111 1111 11111 111    
( Solution ) Les balises d'ouverture HTML commencent par <et se terminent par >. Les balises de fermeture HTML commencent par une séquence de caractères </et se terminent par le caractère >. Le nom de la balise est contenu entre ces caractères. Pouvez-vous écrire une expression régulière pour capturer uniquement les noms dans les balises suivantes ? (Vous pourrez peut-être résoudre ce problème sans utiliser de groupes sans capture. Essayez de résoudre ce problème de deux manières ! Une fois avec des groupes et une fois sans.)
modèle:
chaîne :   <p> </span> <div> </kbd> <link> 
correspondances : ^^^ ^^^^^^ ^^^^^ ^^^^^^ ^^^^^^ 
groupe :    1 1111 111 111 1111    
( Solution utilisant des groupes non capturants ) ( Solution sans utiliser des groupes non capturants ) <h2>Étape 17 : Backlinks \Net groupes de capture nommés</h2> RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 - 3Bien que je vous ai prévenu dans l'introduction, essayer de créer un analyseur HTML à l'aide d'expressions régulières est généralement conduit au chagrin, ce dernier exemple est une belle transition vers une autre fonctionnalité (parfois) utile de la plupart des expressions régulières : les références arrière. Les backlinks sont comme des groupes répétitifs où vous pouvez essayer de capturer deux fois le même texte. Mais ils diffèrent sur un aspect important : ils ne captureront que le même texte, caractère par caractère. Alors qu'un groupe répétitif nous permettra de capturer quelque chose comme ceci :
motif : (he(?:[az])+) 
chaîne :   heyabcdefg hey heyo hejaune heyyyyyyyyy 
correspondances : ^^^^^^^^^^ ^^^ ^^^^ ^^^^^^^^ ^^^ ^^^^^^^^ 
groupe :    1111111111 111 1111 11111111 11111111111    
( Exemple ) ... alors le backlink correspondra uniquement à ceci :
motif : (he([az])(\2+)) 
chaîne : heyabcdefg hey heyo heyellow heyyyyyyyyy 
correspondances :                              ^^^^^^^^^^^ 
groupe :                                 11233333333    
( Exemple ) Les groupes de capture répétitifs sont utiles lorsque vous souhaitez faire correspondre le même modèle à plusieurs reprises, tandis que les backlinks sont utiles lorsque vous souhaitez faire correspondre le même texte. Par exemple, nous pourrions utiliser un backlink pour essayer de trouver des balises HTML d’ouverture et de fermeture correspondantes :
motif : <(\w+)[^>]*>[^<]+<\/\1> 
chaîne :   <span style="color: red">hé</span> 
correspondances : ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
groupe :    1111    
( Exemple ) <mark>Veuillez noter</mark> qu'il s'agit d'un exemple extrêmement simplifié et je vous recommande fortement de ne pas essayer d'écrire un analyseur HTML basé sur une expression régulière. Il s’agit d’une syntaxe très complexe qui vous rendra probablement malade. Les groupes de capture nommés sont très similaires aux backlinks, je vais donc les aborder brièvement ici. La seule différence entre les références arrière et un groupe de capture nommé est que... un groupe de capture nommé a un nom :
motif : <(?<tag>\w+)[^>]*>[^<]+<\/(?P=tag)></tag> 
chaîne :   <span style="color: red">hé< /span> 
correspondances : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
groupe :    1111    
( Exemple ) Vous pouvez créer un groupe de capture nommé en utilisant la syntaxe (?<name>...) ou (?'name'...) (expression régulière compatible .NET) ou avec cette syntaxe (?P<name>. ..) ou (?P'name'...) (expression régulière compatible Python). Puisque nous utilisons PCRE (Perl Compatible Regular Expression) qui prend en charge les deux versions, nous pouvons utiliser l'une ou l'autre ici. (Java 7 a copié la syntaxe .NET, mais uniquement la version entre crochets. Note du traducteur) Pour répéter un groupe de capture nommé plus tard dans une expression régulière, nous utilisons \<kname> ou \k'name' (.NET) ou (? P= nom) (Python). Encore une fois, PCRE prend en charge toutes ces différentes options. Vous pouvez en savoir plus sur les groupes de capture nommés ici , mais c'est l'essentiel de ce que vous devez vraiment savoir à leur sujet. <h3>Tâche pour nous aider :</h3> Utilisez des backlinks pour m'aider à me souvenir... euh... du nom de cette personne.
modèle:
chaîne : "Salut, je m'appelle Joe." [plus tard] "Comment s'appelle ce type ? Joe ?"
correspondances :        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ 
groupe :                  111    
( Solution ) <h2>Étape 18 : analyse en avant et en arrière</h2> RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 - 4Nous allons maintenant nous plonger dans certaines des fonctionnalités avancées des expressions régulières. J'utilise tout jusqu'à l'étape 16 assez souvent. Mais ces dernières étapes sont réservées aux personnes qui utilisent très sérieusement les regex pour faire correspondre des expressions très complexes. En d’autres termes, des maîtres des expressions régulières. "Looking Forward" et "Looking Back" peuvent sembler assez compliqués, mais ils ne le sont pas vraiment. Ils vous permettent de faire quelque chose de similaire à ce que nous avons fait plus tôt avec les groupes non capturants : vérifier s'il y a du texte immédiatement avant ou immédiatement après le texte réel que nous voulons faire correspondre. Par exemple, supposons que nous souhaitions faire correspondre uniquement les noms de choses que les gens aiment, mais seulement s'ils sont enthousiastes à ce sujet (uniquement s'ils terminent leur phrase par un point d'exclamation). Nous pourrions faire quelque chose comme :
motif : (\w+)(?=!) 
chaîne : J'aime le bureau. J'apprécie l'agrafeuse. J'adore la lampe !
matchs :                                           ^^^^ 
groupe :                                              1111    
( Exemple ) Vous pouvez voir comment le groupe de capture ci-dessus (\w+), qui correspond généralement à l'un des mots du passage, ne correspond qu'au mot lampe. L'anticipation positive (?=!)signifie que nous ne pouvons faire correspondre que les séquences qui se terminent par, !mais que nous ne faisons pas correspondre le caractère de point d'exclamation lui-même. Il s'agit d'une distinction importante car avec les groupes qui ne capturent pas, nous faisons correspondre le personnage mais ne le capturons pas. Avec les analyses anticipées et ultérieures, nous utilisons un caractère pour construire notre expression régulière, mais nous ne le comparons même pas à lui-même. Nous pourrons le faire correspondre plus tard dans notre expression régulière. Il existe quatre types d'anticipation et d'anticipation : une anticipation positive (?=...), une anticipation négative (?!...), une anticipation positive (?<=...) et une anticipation négative (?<!. ..) . Ils font ce à quoi ils ressemblent : une analyse anticipée et une analyse positive permettent au moteur d'expression régulière de continuer à correspondre uniquement lorsque le texte contenu dans l'analyse anticipée/respective correspond réellement. Les analyses anticipées et ultérieures négatives font le contraire : elles permettent à l'expression régulière de correspondre uniquement lorsque le texte contenu dans l'analyse anticipée/respective ne correspond pas. Par exemple, nous souhaitons faire correspondre les noms de méthodes uniquement dans une chaîne de séquences de méthodes, et non dans l'objet sur lequel elles opèrent. Dans ce cas, chaque nom de méthode doit être précédé d'un .. Une expression régulière utilisant un simple retour en arrière peut être utile ici :
modèle : (?<=\.)(\w+) 
chaîne : monArray. flatMap.aggregate.summarise.print !
correspondances :         ^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^ 
groupe :            1111111 111111111 111111111 11111    
( Exemple ) Dans le texte ci-dessus, nous faisons correspondre n'importe quelle séquence de caractères de mots \w+, mais seulement s'ils sont précédés du caractère .. Nous pourrions obtenir quelque chose de similaire en utilisant des groupes non capturants, mais le résultat est un peu plus compliqué :
modèle : (?:\.)(\w+) 
chaîne : myArray .flatMap.aggregate.summarise.print !
correspondances :        ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^ 
groupe :            1111111 111111111 111111111 11111    
( Exemple ) Même s'il est plus court, il correspond à des caractères dont nous n'avons pas besoin. Bien que cet exemple puisse paraître trivial, les analyses anticipées et ultérieures peuvent vraiment nous aider à nettoyer nos expressions régulières. <h3>Il en reste très peu avant l'arrivée ! Les 2 tâches suivantes nous en rapprocheront d'un pas :</h3> Le lookbehind négatif (?<!...) permet au moteur d'expression régulière de continuer à essayer de trouver une correspondance uniquement si le texte contenu à l'intérieur du lookbehind négatif n'est pas affiché jusqu'au reste du texte, avec lequel vous devez trouver une correspondance. Par exemple, nous pourrions utiliser une expression régulière pour faire correspondre uniquement les noms de famille des femmes participant à une conférence. Pour ce faire, nous souhaitons nous assurer que le nom de famille de la personne ne soit pas précédé d'un Mr.. Pouvez-vous écrire une expression régulière pour cela ? (Les noms de famille peuvent être supposés comporter au moins quatre caractères.)
modèle:
chaîne : M. Brun, Mme. Smith , Mme. Jones , Miss Daisy , M. Vert
matchs :                ^^^^^ ^^^^^ ^^^^^ 
groupe :                   11111 11111 11111    
( Solution ) Disons que nous effaçons une base de données et que nous avons une colonne d'informations qui représente des pourcentages. Malheureusement, certaines personnes ont écrit des nombres sous forme de valeurs décimales dans la plage [0,0, 1,0], tandis que d'autres ont écrit des pourcentages dans la plage [0,0%, 100,0%], et d'autres encore ont écrit des valeurs en pourcentage, mais ont oublié le signe de pourcentage littéral %. En utilisant une anticipation négative (?!...), pouvez-vous marquer uniquement les valeurs qui devraient être des pourcentages mais qui manquent de chiffres %? Il doit s'agir de valeurs strictement supérieures à 1,00, mais sans fin %. (Aucun nombre ne peut contenir plus de deux chiffres avant ou après la virgule.) <mark>Notez</mark> que cette solution est extrêmement difficile . Si vous pouvez résoudre ce problème sans regarder ma réponse, alors vous possédez déjà d’énormes compétences en expressions régulières !
modèle:
chaîne : 0,32 100,00 5,6 0,27 98 % 12,2 % 1,01 0,99 % 0,99 13,13 1,10 
correspondances :      ^^^^^^ ^^^ ^^^^ ^^^^^ ^^^^ 
groupe :         111111 111 1111 11111 1111    
( Solution ) <h2>Étape 19 : Conditions dans les expressions régulières</h2> RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 - 5Nous avons maintenant atteint le point où la plupart des gens n'utiliseront plus les expressions régulières. Nous avons probablement couvert 95 % des cas d'utilisation d'expressions régulières simples, et tout ce qui est effectué aux étapes 19 et 20 est généralement effectué par un langage de manipulation de texte plus complet comme awk ou sed (ou un langage de programmation à usage général). Cela dit, passons à autre chose, juste pour que vous sachiez ce qu'une expression régulière peut réellement faire. Bien que les expressions régulières ne soient pas complètes de Turing , certains moteurs d'expressions régulières offrent des fonctionnalités très similaires à celles d'un langage de programmation complet. L'une de ces caractéristiques est la « condition ». Les conditions Regex autorisent les instructions if-then-else, où la branche choisie est déterminée soit par le « look forward » ou le « look back » dont nous avons entendu parler à l'étape précédente. Par exemple, vous souhaiterez peut-être faire correspondre uniquement les entrées valides dans une liste de dates :
modèle : (?<=Feb)([1-2][0-9])|(?<=Mar )([1-2][0-9]|3[0-1]) 
chaîne : Dates travaillées : 28 février , 29 février , 30 février , 30 mars , 31 mars  
matchs :                   ^^ ^^ ^^ ^^ 
groupe :                      11 11 22 22    
( Exemple ) <mark>Notez</mark> que les groupes ci-dessus sont également indexés par mois. Nous pourrions écrire une expression régulière pour les 12 mois et capturer uniquement les dates valides, qui seraient ensuite combinées en groupes indexés par mois de l'année. Ce qui précède utilise une sorte de structure de type if qui ne recherchera les correspondances dans le premier groupe que si "Feb" précède un nombre (et de même pour le second). Et si nous souhaitions utiliser un traitement spécial uniquement pour février ? Quelque chose comme "si le numéro est précédé de "Février", faites ceci, sinon faites cette autre chose." Voici comment procéder avec les conditions :
modèle : (?(?<=Feb)([1-2][0-9])|([1-2][0-9]|3[0-1])) 
chaîne : Dates de travail : 28 février , 29 février , 30 février, 30 mars et 31 mars  
matchs :                   ^^ ^^ ^^ ^^ 
groupe :                      11 11 22 22    
( Exemple ) La structure if-then-else ressemble à (?(If)then|else), où (if) est remplacé par "look forward" ou "look back". Dans l'exemple ci-dessus, (if) s'écrit (?<=Feb). Vous pouvez voir que nous avons fait correspondre des dates supérieures à 29, mais seulement si elles ne suivaient pas « février ». L'utilisation de lookbehinds dans les expressions conditionnelles est utile si vous souhaitez vous assurer que la correspondance est précédée d'un texte. Les conditions d’anticipation positives peuvent prêter à confusion car la condition elle-même ne correspond à aucun texte. Donc, si vous souhaitez que la condition if ait une valeur, elle doit être comparable à l'anticipation comme ci-dessous :
modèle : (?(?=exact)exact|else)wo 
chaîne : exact else exacttwo elsewo  
correspondances :            ^^^^^^^ ^^^^^^
( Exemple ) Cela signifie que les conditions d'anticipation positives sont inutiles. Vous vérifiez si ce texte est devant, puis fournissez un modèle correspondant à suivre lorsqu'il l'est. L’expression conditionnelle ne nous aide pas du tout ici. Vous pouvez également simplement remplacer ce qui précède par une expression régulière plus simple :
motif : (?:exact|else)wo 
chaîne : exact else exacttwo elsewo  
correspondances :            ^^^^^^^ ^^^^^^
( Exemple ) Ainsi, la règle générale pour les expressions conditionnelles est la suivante : tester, tester et tester à nouveau. Sinon, les solutions que vous pensez évidentes échoueront de la manière la plus excitante et la plus inattendue :) <h3>Nous arrivons ici au dernier bloc de tâches qui nous sépare de la 20ème étape finale :</h3> Écrivez une expression régulière qui utilise une expression conditionnelle d’anticipation négative pour tester si le mot suivant commence par une lettre majuscule. Si tel est le cas, saisissez une seule lettre majuscule, puis les lettres minuscules. Si ce n'est pas le cas, saisissez n'importe quel caractère de mot.
modèle:
chaîne :   Jones Smith 9sfjn Hobbes 23r4tgr9h CSV Csv vVv 
correspondances : ^^^^^ ^^^^^ ^^^^^ ^^^^^^ ^^^^^^^^^^ ^^^ ^^^ 
groupe :    22222 22222 11111 222222 111111111 222 111    
( Solution ) Écrivez une expression conditionnelle négative qui capture le texte ownsuniquement s'il n'est pas précédé de texte cl, et qui capture le texte oudsuniquement lorsqu'il est précédé de texte cl. (Un exemple un peu artificiel, mais que pouvez-vous faire...)
modèle:
string : Ces clowns possèdent des nuages . ouds.
correspondances :              ^^^^ ^^^^   
( Solution ) <h2>Étape 20 : Récursion et étude plus approfondie</h2> RegEx : 20 petites étapes pour maîtriser les expressions régulières.  Partie 4 à 6En fait, il y a beaucoup de choses qui peuvent être intégrées dans une introduction en 20 étapes à n'importe quel sujet, et les expressions régulières ne font pas exception. Il existe de nombreuses implémentations et normes différentes pour les expressions régulières disponibles sur Internet. Si vous voulez en savoir plus, je vous suggère de consulter le merveilleux site regularexpressions.info , c'est une référence fantastique et j'y ai certainement beaucoup appris sur les expressions régulières. Je le recommande vivement, ainsi que regex101.com pour tester et publier vos créations. Dans cette dernière étape, je vais vous donner un peu plus de connaissances sur les expressions régulières, à savoir comment écrire des expressions récursives. Les récursions simples sont assez simples, mais réfléchissons à ce que cela signifie dans le contexte d'une expression régulière. La syntaxe de la récursivité simple dans une expression régulière s'écrit comme ceci : (?R)?. Mais bien entendu, cette syntaxe doit apparaître dans l’expression elle-même. Ce que nous allons faire, c'est imbriquer l'expression en elle-même, un nombre arbitraire de fois. Par exemple:
motif : (hey(?R)?oh) 
chaîne :   heyoh heyyoh heyheyohoh hey oh heyhey hey heyheyohoh  
correspondances : ^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ 
groupe :    11111 1111111111 1111111111    
( Exemple ) Puisque l'expression imbriquée est facultative ( (?R)follow ?), la correspondance la plus simple consiste simplement à ignorer complètement la récursion. Donc, hey, puis ohcorrespond à ( heyoh). Pour faire correspondre une expression plus complexe que celle-ci, nous devons trouver cette sous-chaîne correspondante imbriquée à l’intérieur d’elle-même au point de l’expression où nous avons inséré (?R)la séquence. En d’autres termes, nous pourrions trouver heyheyohoh ou heyheyheyohohoh, et ainsi de suite. L'un des avantages de ces expressions imbriquées est que, contrairement aux références arrière et aux groupes de capture nommés, elles ne vous limitent pas au texte exact que vous avez fait correspondre précédemment, caractère par caractère. Par exemple:
motif : ([Hh][Ee][Yy](?R)?oh) 
chaîne :   heyoh heyyoh hEyHeYohoh hey oh heyhey hEyHeYHEyohohoh  
correspond : ^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^ 
groupe :    11111 1111111111 111111111111111    
( Exemple ) Vous pouvez imaginer que le moteur d'expression régulière copie et colle littéralement votre expression régulière dans lui-même un nombre arbitraire de fois. Bien sûr, cela signifie que parfois, il se peut que cela ne fasse pas ce que vous auriez pu espérer :
modèle : ((?:\(\*)[^*)]*(?R)?(?:\*\))) 
chaîne : (* commentaire (* imbriqué *) non *)
matchs :            ^^^^^^^^^^^^ 
groupe :               111111111111    
( Exemple ) Pouvez-vous expliquer pourquoi cette expression régulière n'a capturé que le commentaire imbriqué et non le commentaire externe ? Une chose est sûre : lorsque vous écrivez des expressions régulières complexes, testez-les toujours pour vous assurer qu'elles fonctionnent comme vous le pensez. Ce rallye à grande vitesse sur les routes des expressions régulières touche à sa fin. J'espère que vous avez apprécié ce voyage. Bon et enfin, je laisserai ici, comme je l'ai promis au début, plusieurs liens utiles pour une étude plus approfondie de la matière :
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION