Nous relevons le défi de Callum Macrae à 100%

Je suggère d'essayer de résoudre 10 tests de regex de Callum Macrae. Contrairement à mon analyse précédente du défi , il n'y a pas de tâches franchement simples et même moyennes. Comme on dit - seulement regex, seulement hardcore.


Comme le défi est assez compliqué, il n'est pas nécessaire de suivre toutes les règles comme moi, toute réussite au test est à 100% - cela signifie que vous êtes un super professionnel. Bienvenue!


Oui, je sais, ce défi a déjà été publié une fois. Mais l'auteur de l'article n'a pas présenté de solutions de travail, et dans les commentaires, les gens ne pouvaient pas résoudre 4 problèmes supplémentaires et, le plus souvent, ne comprenaient même pas le sens de la tâche et ce qu'ils attendaient d'eux.


Par conséquent, je le poste à nouveau, avec une traduction détaillée, une explication et tous les petits pains.


Tâche 1 - mettre en évidence les mots en double


http://callumacrae.imtqy.com/regex-tuesday/challenge1.html


Il y a un ensemble de phrases, dans cette phrase il peut y avoir des mots en double. Il est nécessaire de mettre en évidence les mots qui se répètent.


Un exemple:


This is is a test 

Dans ce cas, le mot "est" est répété deux fois, mis en évidence en gras:


 This is <strong>is</strong> a test 

Indice

Il est nécessaire de trouver des répétitions de mots, et les mots sont séparés par un espace, donc - un caractère d'espacement est requis. Dans les expressions régulières, il est techniquement possible de trouver des répétitions uniquement via le lien arrière.


Solution

Expression:


 /\b([\w']+)\s(\1)\b/gi 

Remplacement:


 $1 <strong>$2</strong> 

Solution d'analyse
  • "\ b" - devrait commencer par la limite du mot
  • "([\ w '] +)" - n'importe quel nombre de lettres, de chiffres et d'apostrophe (vous pouvez également le résoudre avec tout autre qu'un espace ) et assurez-vous de le capturer dans un groupe, car Ensuite, trouvez la répétition de ce groupe.
  • "\ s (\ 1)" - parce que nous savons que la répétition vient après l'espace, nous mettons un espace "\ s" et ensuite nous écrivons qu'après cela la répétition du premier groupe précédemment capturé "(\ 1)" doit suivre.
  • "\ b" - la répétition doit se terminer par la limite du mot, sinon nous risquons de ne capturer qu'une partie du mot.

Tâche 2 - Niveaux de gris


http://callumacrae.imtqy.com/regex-tuesday/challenge2.html


Il existe des codes couleurs dans différents formats, la tâche consiste à trouver toutes les nuances de gris.


Exemples de codes valides:


 #eEe #6F6F6F rgb(2.5, 2.5,2.5) hsl(0, 10%, 100%) 

Exemples de codes invalides:


 #eEf #11111e rgb(1.5%, 1.5%, 1.6%) hsl(20, 20%, 20%) 

Explications du code

La question la plus importante dans cette tâche est ce qui est considéré comme gris.


Selon Wikipedia, le gris est:


Beaucoup de couleurs obtenues en combinant les trois couleurs primaires du modèle de couleur RVB - rouge, vert et bleu à concentrations égales .

Les codes commençant par # sont au format hexadécimal, il se présente sous deux formes. Abrégé, trois caractères (#rgb) et complet, six caractères $ rrggbb. Où r, g, b sont les trois couleurs primaires.
Les codes rgb (r, g, b) sont exactement les mêmes, ils ne sont écrits qu'en chiffres de 0 à 255.
Le format hsl est un peu plus compliqué, les chiffres ici signifient le ton, la saturation et la légèreté. Pour comprendre dans quelles conditions trois couleurs primaires sont obtenues dans des proportions égales, par exemple, vous pouvez jouer avec cet éditeur visuel.


Indice

Pour l'hex abrégé, l'occurrence correcte sera la répétition des trois caractères, par exemple #aaa. Pour un hexagone complet, répétez deux caractères, par exemple #efefef. Pour la RVB numérique, répétez les chiffres, par exemple RVB (2, 2, 2). Comprendre le format hsl est un peu plus compliqué, mais sachant toujours ce qui précède, vous pouvez comprendre qu'ici la couleur grise est la couleur à laquelle le ton est 0 ou la saturation est 0 ou 100.


En conséquence, comme dans la tâche précédente, vous devez utiliser le lien arrière. L'expression régulière résultante sera grande (ce qui est normal), car vous devez prendre en compte de nombreuses options différentes, y compris celles écrites de manière incorrecte.


Solution
 /^(?:#(\w)\1\1|#(\w{2})\2\2|rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\)|rgba\(([\d.]+%?),[0 ]*\4,[0 ]*\4,[^)]+\)|hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\))$/i 

Solution d'analyse

Un rugulaire distinct est écrit pour chaque couleur, nous les analyserons séparément:


 #(\w)\1\1 

  • "(\ w)" prend un seul caractère du groupe.
  • "\ 1 \ 1" - et indiquez qu'il doit être répété 2 fois.

Pour deux personnages la même chose - je ne répéterai pas.


 rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\) 

Je voudrais écrire "rgba?", Mais un cas est possible lorsque le quatrième paramètre est spécifié dans rgb (), donc rgb et rgba doivent être décrits séparément:


  • "\ d {1,2} | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]" - la plage va de 0 à 255. Je ne vais pas l'analyser en détail, vous pouvez regarder la tâche 5 ici .
  • "(?: \. \ d +)?" - un groupe optionnel dont le numéro n'est pas attribué. Un point et un nombre après un point sont possibles (c'est pour les nombres non entiers).
  • ", []? [0] * \ 3" - une virgule obligatoire, suivie de 0 ou 1 espace, 0 ou plusieurs zéros, après quoi la valeur du groupe précédemment capturé doit être répétée.

Dans rgba () - la même chose, mais 4 paramètres sont requis.


 hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\) 

Ici, dans le bon sens, vous devez également séparer hsl et hsla, mais il n'y a pas un tel cas dans les cas de test, nous allons donc écrire un petit "hsla?".


  • "[\ d.] +, [] *" - vient d'abord le nombre requis "[\ d.] +" (y compris pas un nombre entier) avec une virgule obligatoire et un espace optionnel "[] *".
  • "(0% [^)] + | [\ d.] +%, [] * (0 | 100)% [^)] *" - et puis deux options sont possibles: 1) où 0% vient en premier et puis tout caractère autre que le caractère de fermeture du crochet [^)] +; 2) il existe un nombre quelconque avec un signe de pourcentage obligatoire et une virgule "[\ d.] +%", Puis 0% ou 100% "(0 | 100)%".

Tâche 3 - Rechercher des dates


http://callumacrae.imtqy.com/regex-tuesday/challenge3.html


Il y a une liste de dates, à partir de ces dates, trouvez des dates de 1000 à 2012 inclusivement écrites au format AAAA / MM / JJ HH: MM (: SS). Où chaque lettre est un nombre requis et entre parenthèses n'est pas une condition préalable.


Exemple


 2001/09/30 23:59:11 

Indice

"[0-9]" n'est pas une plage de nombres, c'est une expression qui signifie qu'un seul caractère de 0-9 est valide. Dans les expressions régulières, il n'y a pas de plage pour les grands nombres, mais à partir de ces petits morceaux, vous pouvez créer une expression régulière couvrant la plage souhaitée. Exemple: "1 [0-9]" - une plage de 10 à 19.


Solution
 /^(1[\d]{3}|200\d|201[0-2])\/(0[1-9]|1[0-2])\/(0[1-9]|1[0-9]|2[0-9]|3[0-2])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][\d])(:([0-5][\d]))?$/ 

Solution d'analyse
  • L'année valide est "(1 [\ d] {3} | 200 \ d | 201 [0-2])", où dans l'ordre de 1000 à 1999, de 2000 à 2009, de 2010 à 2012.
  • Mois "(0 [1-9] | 1 [0-2])". Du 01 au 09 et du 10 au 12.
  • Jour "(0 [1-9] | 1 [0-9] | 2 [0-9] | 3 [0-2])". Du 01 au 09 et du 10 au 19, du 20 au 29 et du 30 au 32.
  • Heure "(0 [0-9] | 1 [0-9] | 2 [0-3])". Du 00 au 09 et du 10 au 19, du 20 au 23.
  • Minute "([0-5] [\ d])". 00 à 59
  • (: ([0-5] [\ d]))? - secondes optionnelles, de 00 à 59.

Tâche 4 - italique


http://callumacrae.imtqy.com/regex-tuesday/challenge4.html


Il y a un texte avec le balisage MarkDown (comme sur le Habré). Vous devez écrire une expression régulière qui remplacera les mots entre les astérisques par la balise <em>.


Exemple


 *This text is italic.* -> <em>This text is italic.</em> 

Indice

Vous devez trouver un astérisque avant et après lequel il n'y a pas d'autre astérisque. Il n'y a que de l'avant et de l'avant et de l'arrière (le plus simple, mais pas multi-navigateur.)


Solution

Expression:


 /(^|[^*])\*([^*].*?[^*]|[^*])\*((?!\*)|$)/g 

Remplacement:


 $1<em>$2</em> 

Solution d'analyse
  • "(^ | [^ *])" - nous commencerons soit au début de la ligne, soit à partir de n'importe quel caractère à l'exception d'un astérisque. Le groupe doit capturer ce symbole et le placer avant la balise <em>.
  • (?
  • "([^ *]. *? [^ *] | [^ *])" - au milieu, nous avons "[^ *]. *? [^ *]" Tout texte qui ne doit pas commencer ni se terminer par un astérisque et une expression ou "| [^ *]" juste pour prendre en compte un seul caractère à l'intérieur de la balise (il n'est pas nécessaire de passer le test).

Tâche 5 - Format des nombres


http://callumacrae.imtqy.com/regex-tuesday/challenge5.html


Dans la liste des numéros, sélectionnez uniquement les numéros au format correct. Il est généralement admis d'écrire des nombres de droite à gauche, divisés en groupes de trois chiffres chacun.


Exemples de numéros correctement enregistrés:


 1,024 8,205,500.4672 10.444444444444 30 000,7302 

Indice

Il est important de considérer que les nombres sont écrits exactement de droite à gauche, et non vice versa. Cela signifie qu'un nombre peut commencer par 1 à 3 chiffres, puis qu'il ne peut y avoir que trois chiffres dans un groupe. Dans la partie non entière, il peut y avoir autant de nombres que vous le souhaitez (ou pas du tout). Tenez compte du fait que le séparateur de groupes peut être une virgule ou un espace et que le séparateur d'une partie entière et non entière peut être une virgule ou un point.


Solution

Expression:


 /^\d{1,3}([ ,]\d{3})*([.,]\d+)?$/ 

Solution d'analyse
  • "^ \ d {1,3}" - au début de 1 à 3 chiffres.
  • "([,] \ d {3}) *" - plus un séparateur et un groupe de 3 nombres, un astérisque indique que notre format peut se produire 0 ou plusieurs fois.
  • "([.,] \ d +)? $" - à la fin est un groupe avec un séparateur et un nombre, le point d'interrogation est un quantificateur qui dit que la présence de la partie non entière n'est pas une condition préalable.

Tâche 6 - adresses IP


http://callumacrae.imtqy.com/regex-tuesday/challenge6.html


Dans la liste des adresses IP dans une variété de formats, recherchez des adresses IP valides. Peut-être la tâche la plus morne de toutes. Pas tellement super compliqué, combien triste.


Exemples d'entrées d'adresse IP valides et explication:


  • 192.0.2.235 - décimal avec points.
  • 0300.0000.0002.0353 - octal avec des points.
  • 0xC0.0x00.0x02.0xEB - hexadécimal avec des points.
  • 0xC00002EC - hexadécimal.
  • 287454020 - décimal.
  • 030000001353 - octal.

Mélanger différents formats est mauvais. Surtout les chiffres. La situation est encore compliquée par le fait que les formats d'adresses IP avec des points peuvent être mélangés, par exemple - 0xFF.255.0377.0x12. Personnellement, je pense que c'est une mauvaise pratique, mais néanmoins, selon le test, de telles options sont possibles et doivent donc être prises en compte.


Indice
  • 192.0.2.235 - décimal avec points. Une notation commune peut être exprimée de 1 à 3 chiffres entre les points (valeurs de 0 à 255).
  • 0300.0000.0002.0353 - octal avec des points. 4 chiffres entre les points avec des valeurs de 0 à 7.
  • 0xC0.0x00.0x02.0xEB - hexadécimal avec des points. Quatre caractères entre les points. En tête de "0x", puis deux caractères (par chiffres ou de "a" à "f").
  • 0xC00002EC - hexadécimal. "0x", puis 8 caractères (valeurs numériques ou de "a" à "f").
  • 287454020 - décimal. Tous les nombres compris entre 0 et 4294967295.
  • 030000001353 - octal. 0 en tête. Les nombres vont de 0 à 7. La plage va de 0 à 07777777777777.

L'expression régulière sera géniale.


Solution
 /^((((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4}))\.){3}(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4})))|(0x[\da-f]{8})|(0([0-7]{1,11}))|(2874540[2-8][0-9]|28745409[0-9]|287454[1-9][0-9]{2}|28745[5-9][0-9]{3}|2874[6-9][0-9]{4}|287[5-9][0-9]{5}|28[89][0-9]{6}|29[0-9]{7}|[3-9][0-9]{8}|[1-3][0-9]{9}|4[01][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[01][0-9]{2}|42949672[0-8][0-9]|429496729[0-5]))$/i 

Solution d'analyse

Pour les adresses IP avec des points, le mélange est possible, nous écrivons donc les options via "|" par un tel modèle: ((décimal | hexadécimal | octal).) {3} (décimal | hexadécimal | octal).


  • "(\ d | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5])" - pour décimal avec point d'enregistrement.
  • "(0x [\ da-f] {2})" - pour hexadécimal avec un point d'enregistrement.
  • "([0-7] {4})" - pour octal avec un point d'enregistrement.

Et d'autres formats d'enregistrement:


  • "(0x [\ da-f] {8})" - pour la notation hexadécimale.
  • "(2874540 [2-8] [0-9] | 28745409 [0-9] | 287454 [1-9] [0-9] {2} | 28745 [5-9] [0-9] {3} | 2874 [6-9] [0-9] {4} | 287 [5-9] [0-9] {5} | 28 [89] [0-9] {6} | 29 [0-9] {7} | [3-9] [0-9] {8} | [1-3] [0-9] {9} | 4 [01] [0-9] {8} | 42 [0-8 ] [0-9] {7} | 429 [0-3] [0-9] {6} | 4294 [0-8] [0-9] {5} | 42949 [0-5] [0-9 ] {4} | 429496 [0-6] [0-9] {3} | 4294967 [01] [0-9] {2} | 42949672 [0-8] [0-9] | 429496729 [0-5 ]) "- pour la notation décimale. Et ici, je dois admettre, pour une expression plus courte, j'ai triché en n'incluant que des adresses IP décimales dans la plage de test. Pour le bien, ici, vous devez considérer tous les nombres de 0 à 4294967295. Écrire ceci manuellement n'est pas une tâche reconnaissante, nous l'utilisons donc .
  • (0 ([0-7] {1,11})) - pour la notation octale.

Tâche 7 - URL


http://callumacrae.imtqy.com/regex-tuesday/challenge7.html


Dans la liste des URL, trouvez valide.


Exemples d'adresses valides:


 http://ab https://example.com/ http://test.this-test.com/ http://1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 

Indice

L'adresse doit nécessairement commencer à http: // ou https: //, et se terminer par une barre oblique, une lettre (s'il s'agit d'un domaine) ou un numéro si une adresse IP. Chaque domaine peut avoir un sous-domaine. Selon la norme, la longueur de chaque domaine ne peut pas dépasser 63 caractères avec une longueur totale de 255 caractères . Un domaine imbriqué dans un sous-domaine limité à 127 domaines . Malheureusement, le moteur JavaScript Regex n'activera pas complètement ces restrictions, mais vous pouvez écrire une expression qui sera à peu près conforme aux règles et réussira le test. Biffé ce qui peut être contourné en ajustant d'autres paramètres.


Solution
 /^https?:\/\/(((\b[az\d-]{1,63}\b)\.){1,40}(\b[az\d-]{1,63}\b))\/?$/i 

Solution d'analyse
  • "^ https?: \ / \ /" - http: // ou https: //

Analysons-le séparément ((\ b [az \ d -] {1,63} \ b).) {1,40}


  • "\ b" à la fin et au début du domaine pour vous assurer que le domaine ne démarre pas et ne se termine pas par un élément non valide.
  • "[az \ d -] {1,63}" - à l'intérieur du nom de domaine, les lettres, les chiffres et les tirets sont autorisés à l'intérieur
  • "{1.63}" - tout cela ne dépasse pas 63 caractères.
  • "((nom-de-domaine).) {1,40}" - Je voudrais mettre 127 ici, mais dans les expressions régulières le quantificateur {,} signifie l'intervalle de répétition. Dans le cas de l'utilisation de [] {}, c'est le nombre de caractères, mais dans le cas sans [], c'est exactement le nombre de fois que le modèle est répété (nom de domaine). Par conséquent, nous limitons la répétition à 40 afin de ne pas dépasser la limite de longueur générale, que nous aussi, pour cette raison, ne pouvons pas strictement fixer.

Tâche 8 - Répéter les éléments


http://callumacrae.imtqy.com/regex-tuesday/challenge8.html


La tâche est très similaire à la tâche 1 à bien des égards, mais ici, vous devez trouver et mettre en évidence les éléments répétés de la liste MarkDown avec deux étoiles.


Une telle liste:


 * Repeated list item * Repeated list item 

Doit être converti en ceci:


 * Repeated list item * **Repeated list item** 

Indice

Nous utilisons un lien de retour, un caractère de saut de ligne, des clés globales, multilignes et insensibles.


Solution

Expression:


 /^(\*\s+([^\n]+)\n\*\s+)(\2)$/gmi 

Remplacement:


 $1**$3** 

Tâche 9 - Liens MarkDown


http://callumacrae.imtqy.com/regex-tuesday/challenge9.html


Remplacez les liens MarkDown valides par des liens html.


Exemple de conversion:


 [Another](http://example.com/) -> <a href="http://example.com/">Another</a> 

Indice

Cela peut être fait sans regarder du tout ou simplement en regardant vers l'avenir. Au lieu de regarder en arrière, c'est un remplacement.


Solution

Expression:


 /(^|\s+)\[([^\]\[]+)\]\s*\((https?:\/\/\b[az\d-]+\b(\.[az-]+)*\.\w+\/*)\)(?=$|\s+)/i 

Remplacement:


 $1<a href="$3">$2</a> 

Solution d'analyse
  • "(^ | \ s +)" - avant le lien MarkDown, le début d'une ligne ou un espace est autorisé. Nous prenons cela dans le groupe pour remplacer l'espace capturé par le remplacement de 1 $.
  • "[([^] [] +)] \ s *" - tous les caractères autres que les guillemets sont autorisés dans l'en-tête.
  • "(https?: \ / \ / \ b [az \ d -] + \ b (. [az -] +) . \ w + \ / )" - nous vérifions que l'adresse URL est valide.
  • "(? = $ | \ s +)" - à la fin soit un espace, soit la fin d'une ligne.

Tâche 10 - Mots clés


http://callumacrae.imtqy.com/regex-tuesday/challenge10.html


Le défi le plus hardcore de tous. En utilisant des expressions régulières avec des remplacements, transformez le texte existant en mots clés séparés par des virgules.


Règles:


  • Les guillemets sont un mot clé.
  • Les noms avec trait d'union sont un mot clé.
  • Le mot peut contenir une apostrophe.
  • Les symboles (; - '") doivent être supprimés.

Voici un exemple:


ne dites pas à Suzie Smith-Hopper que j'ai cassé le cheval jouet de Daniel


Devrait être converti en ceci:


ne dis pas, Suzie, Smith-Hopper, que, moi, cassé, Daniel's, jouet, cheval


Cela ne semble pas compliqué à première vue, mais ce n'est pas le cas. Le fait est qu'un tel problème n'est pas résolu et n'est pas mis en forme définitive avec une seule expression régulière avec un remplacement. Mais les cas de test sont conçus de telle manière que tout de même rendrait possible la solution du problème.


Indice

Il est nécessaire de décider où mettre une virgule, quoi remplacer à côté de cette virgule et de quel côté. Il y a une hypothèse dans le problème - le premier mot dans chaque cas de test ne nécessite aucune modification. Cela signifie que vous devez mettre une virgule à gauche du mot remplacé, à l'exception du premier mot.


Solution

Expression:


 /\s(['"])([^'"]+)\1|(;? |['"]? | ['"]|-{2,})(\w+)/g 

Remplacement:


 ,$2$4 

Solution d'analyse

Puisque nous avons déjà décidé de l'endroit où placer la virgule, nous déciderons de ce que nous allons remplacer cette virgule et quoi supprimer.


  • "\ s (['"]) ([^' "] +)" - remplacez le modèle {espace "du mot par un espace entre guillemets"} par {, mots avec un espace} . "\ s" ici n'est pas juste comme ça, mais afin d'exclure les fausses occurrences avec des guillemets mal placés.
  • "(;? | ['"]? | [' "] | - {2,}) (\ w +)" - il y a ensuite des mots simples qui sont précédés de caractères à supprimer et d'une virgule devant ces mots.

Source: https://habr.com/ru/post/fr474184/


All Articles