Python >> Tutoriel Python >  >> Python Tag >> RegEx

regex pour trouver une paire de chiffres adjacents avec des chiffres différents autour d'eux

Avec regex, il est beaucoup plus pratique d'utiliser un PyPi regex module avec le (*SKIP)(*FAIL) motif basé :

import regex
rx = r'(\d)\1{2,}(*SKIP)(*F)|(\d)\2'
l = ["123456678", "1234566678"]
for s in l:
  print(s, bool(regex.search(rx, s)) )

Voir la démo Python. Sortie :

123456678 True
1234566678 False

Détails de l'expression régulière

  • (\d)\1{2,}(*SKIP)(*F) - un chiffre puis deux occurrences ou plus du même chiffre
  • | - ou
  • (\d)\2 - un chiffre puis le même chiffre.

Le but est de faire correspondre tous les morceaux de 3 chiffres identiques ou plus et de les ignorer, puis de faire correspondre un morceau de deux chiffres identiques.

Voir la démo regex.


J'ai divisé ma réponse en quatre sections.

La première section contient ma solution au problème. Les lecteurs intéressés par rien d'autre peuvent sauter les autres sections.

Les trois sections restantes concernent l'identification des paires de chiffres égaux précédés d'un chiffre différent et suivis d'un chiffre différent. La première des trois sections leur correspond; les deux autres les capturent en groupe.

J'ai inclus la dernière section parce que je voulais partager The Greatest Regex Trick Ever avec ceux qui ne le connaissent pas, parce que je le trouve tellement cool et intelligent, mais simple. C'est documenté ici. Soyez prévenu que, pour créer du suspense, l'auteur de ce lien a inclus un long préambule avant la révélation du roulement de tambour.

Déterminer si une chaîne contient deux chiffres égaux consécutifs précédés d'un chiffre différent et suivis d'un chiffre différent

Vous pouvez tester la chaîne comme suit :

import re

r = r'(\d)(?!\1)(\d)\2(?!\2)\d'
arr = ["123456678", "1123455a666788"]
for s in arr:
  print(s, bool(re.search(r, s)) )

affiche

123456678 True
1123455a666788 False

Exécutez le code Python | Démarrez votre moteur ! 1

Le moteur regex effectue les opérations suivantes.

(\d)    : match a digit and save to capture group 1 (preceding digit)
(?!\1)  : next character cannot equal content of capture group 1
(\d)    : match a digit in capture group 2 (first digit of pair)
\2      : match content of capture group 2 (second digit of pair)
(?!\2)  : next character cannot equal content of capture group 2
\d      : match a digit

(?!\1) et (?!\2) sont des anticipations négatives .

Utilisez la regex de Python module pour faire correspondre des paires de chiffres consécutifs qui ont la propriété souhaitée

Vous pouvez utiliser l'expression régulière suivante avec regex de Python module pour obtenir les paires de chiffres correspondantes.

r'(\d)(?!\1)\K(\d)\2(?=\d)(?!\2)'

Moteur Regex

Le moteur regex effectue les opérations suivantes.

(\d)    : match a digit and save to capture group 1 (preceding digit)
(?!\1)  : next character cannot equal content of capture group 1
\K      : forget everything matched so far and reset start of match
(\d)    : match a digit in capture group 2 (first digit of pair)
\2      : match content of capture group 2 (second digit of pair)
(?=\d)  : next character must be a digit
(?!\2)  : next character cannot equal content of capture group 2

(?=\d) est une anticipation positive . (?=\d)(?!\2) pourrait être remplacé par (?!\2|$|\D) .

Enregistrer des paires de chiffres consécutifs ayant la propriété souhaitée dans un groupe de capture

Une autre façon d'obtenir les paires de chiffres correspondantes, qui ne nécessite pas le module regex, consiste à extraire le contenu du groupe de capture 2 à partir des correspondances de l'expression régulière suivante.

r'(\d)(?!\1)((\d)\3)(?!\3)(?=\d)'

Re moteur

Les opérations suivantes sont effectuées.

(\d)    : match a digit in capture group 1
(?!\1)  : next character does not equal last character
(       : begin capture group 2
  (\d)  : match a digit in capture group 3
  \3    : match the content of capture group 3
)       : end capture group 2
(?!\3)  : next character does not equal last character
(?=\d)  : next character is a digit

Utilisez La plus grande astuce Regex de tous les temps pour identifier les paires de chiffres consécutifs qui ont la propriété souhaitée

Nous utilisons l'expression régulière suivante pour faire correspondre la chaîne.

r'(\d)(?=\1)|\d(?=(\d)(?!\2))|\d(?=\d(\d)\3)|\d(?=(\d{2})\d)'

Lorsqu'il y a une correspondance, nous ne prêtons aucune attention au caractère correspondant, mais examinons le contenu du groupe de capture 4 ((\d{2}) ), comme je l'expliquerai ci-dessous.

L'astuce en action

Les trois premières composantes de l'alternance correspondent aux façons dont une chaîne de quatre chiffres peut ne pas avoir la propriété que les deuxième et troisième chiffres sont égaux, les premier et deuxième sont inégaux et les troisième et quatrième sont égaux. Ce sont :

(\d)(?=\1)        : assert first and second digits are equal    
\d(?=(\d)(?!\2))  : assert second and third digits are not equal
\d(?=\d(\d)\3)    : assert third and fourth digits are equal

Il s'ensuit que s'il y a correspondance d'un chiffre et que les trois premières parties de l'alternance échouent la dernière partie (\d(?=(\d{2})\d) ) doit réussir et le groupe de capture qu'il contient (#4) doit contenir les deux chiffres égaux qui ont les propriétés requises. (Le dernier \d est nécessaire pour affirmer que la paire de chiffres d'intérêt est suivie d'un chiffre.)

S'il y a correspondance, comment déterminer si la dernière partie de l'alternance est celle qui correspond ?

Lorsque cette expression régulière correspond à un chiffre, nous n'avons aucun intérêt à savoir de quel chiffre il s'agissait. Au lieu de cela, nous cherchons à capturer le groupe 4 ((\d{2}) ). Si ce groupe est vide, nous concluons que l'un des trois premiers composants de l'alternance correspondait au chiffre, ce qui signifie que les deux chiffres suivant le chiffre correspondant n'ont pas les propriétés qu'ils sont égaux et sont inégaux aux chiffres qui les précèdent et les suivent .

Si, cependant, le groupe de capture 4 n'est pas vide, cela signifie qu'aucune des trois premières parties de l'alternance ne correspond au chiffre, donc la dernière partie de l'alternance doit correspondre et les deux chiffres suivant le chiffre correspondant, qui sont conservés dans groupe de capture 4, ont les propriétés souhaitées.

1. Déplacez le curseur pour obtenir des explications détaillées.


Inspiré par la réponse ou Wiktor Stribiżew, une autre variante de l'utilisation d'une alternance avec re est de vérifier l'existence du groupe de capture qui contient une correspondance positive pour 2 des mêmes chiffres non entourés par le même chiffre.

Dans ce cas, vérifiez le groupe 3.

((\d)\2{2,})|\d(\d)\3(?!\3)\d

Démo Regex | Démo Python

  • ( Capturez le groupe 1
    • (\d)\2{2,} Capturez le groupe 2 , faites correspondre 1 chiffre et répétez ce même chiffre plus de 2 fois
  • ) Fermer le groupe
  • | Ou
  • \d(\d) Faites correspondre un chiffre, capturez un chiffre dans le groupe 3
  • \3(?!\3)\d Faites correspondre le même chiffre que dans le groupe 3. Faites correspondre le 4 ème chiffre, mais il ne doit pas être le même que le chiffre du groupe 3

Par exemple

import re

pattern = r"((\d)\2{2,})|\d(\d)\3(?!\3)\d"
strings = ["123456678", "12334566", "12345654554888", "1221", "1234566678", "1222", "2221", "66", "122", "221", "111"]

for s in strings:
    match = re.search(pattern, s)
    if match and match.group(3):
        print ("Match: " + match.string)
    else:
        print ("No match: " + s)

Sortie

Match: 123456678
Match: 12334566
Match: 12345654554888
Match: 1221
No match: 1234566678
No match: 1222
No match: 2221
No match: 66
No match: 122
No match: 221
No match: 111

Si, par exemple, 2 ou 3 chiffres seulement peuvent également correspondre, vous pouvez vérifier le groupe 2

(\d)\1{2,}|(\d)\2

Démo Python