Faire correspondre les séquences croissantes / décroissantes en utilisant regex

Je voudrais faire correspondre toute chaîne qui contient uniquement des chiffres qui augmentent ou diminuent. Cela signifie que ces chaînes seraient appariées:

123, 234567, 0123456789, 87654, 321 

Et ceux-ci ne seraient pas:

 7891011, 1234566789, 987865, 134 

Je cherchais une réponse et tout ce que j’ai trouvé, c’est qu’il est impossible de le faire avec regex. Cependant, je voudrais le faire en regex, sinon cela créerait un désordre dans le code.

Merci pour les réponses.

Techniquement, cela est possible avec l’utilisation de lookaheads, mais cela ne sera pas beau.

Logique pour motif ascendant:

  1. Commencer au début de la chaîne
  2. Ne correspond au chiffre actuel que dans le cas où il est suivi du chiffre suivant ou de la fin de la chaîne. Passer à la position suivante.
  3. Répétez 2 jusqu’à la fin de la chaîne.

Exemple pour 123:

  1. Commencer au début de la chaîne
  2. Le symbole actuel est 0? Non, passez.
  3. Le symbole actuel est 1? Oui. Est-il suivi de 2 ou de fin de chaîne? Oui. Ok, allez au symbole suivant.
  4. Le symbole actuel est 2? Oui. Est-il suivi de 3 ou de fin de chaîne? Oui. Ok, allez au symbole suivant.
  5. Le symbole actuel est 3? Oui. Est-il suivi de 4 ou de fin de chaîne? Oui. Ok, allez au symbole suivant.
  6. Le symbole actuel est 4? Le symbole actuel est 5? Non … Est-ce la fin de la ficelle? Oui.

Exemple pour 134:

  1. Commencer au début de la chaîne
  2. Le symbole actuel est 0? Non, passez.
  3. Le symbole actuel est 1? Oui. Est-il suivi de 2 ou de fin de chaîne? No. Erreur, pas de correspondance.

Regex pour correspondre aux modèles ascendants:

 ^(?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?$ 

Visualisation d'expression régulière

Démo Debuggex

Regex pour correspondre aux modèles décroissants:

 ^(?:9(?=8|$))?(?:8(?=7|$))?(?:7(?=6|$))?(?:6(?=5|$))?(?:5(?=4|$))?(?:4(?=3|$))?(?:3(?=2|$))?(?:2(?=1|$))?(?:1(?=0|$))?0?$ 

Visualisation d'expression régulière

Démo Debuggex

Combinés ensemble:

 ^((?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?|(?:9(?=8|$))?(?:8(?=7|$))?(?:7(?=6|$))?(?:6(?=5|$))?(?:5(?=4|$))?(?:4(?=3|$))?(?:3(?=2|$))?(?:2(?=1|$))?(?:1(?=0|$))?0?)$ 

Visualisation d'expression régulière

Démo Debuggex

Regex101 Demo

Le code ne serait pas plus un désordre que la regex pour faire cela. Les expressions régulières sont mauvaises en maths.

Quelque chose comme ça va le faire:

 bool IsSequentiallyIncreasing(ssortingng input) { char? lastDigit = null; foreach (char c in input) { if (!c.IsDigit || (lastDigit != null && c != lastDigit + 1)) { return false; } lastDigit = c; } return true; } 

Ainsi, vous passez en revue tous les caractères de la chaîne et dès que vous rencontrez un non-chiffre ou un chiffre qui n’est pas le dernier chiffre + 1, vous retournez false.

Et faites de même pour décroissant, et vous pouvez simplement appeler IsSequentiallyIncreasing(input) || IsSequentiallyDecreasing(input) IsSequentiallyIncreasing(input) || IsSequentiallyDecreasing(input) . Je vous laisse le soin d’append le traitement des erreurs et de fusionner les deux méthodes en une.

il n’y a pas de motif regex qui puisse le faire, mais vous pouvez utiliser regex pour aider à collecter ces éléments

 List oMatches = new List(); Ssortingng sData = "123, 234567, 0123456789, 87654, 321 , 7891011, 1234566789, 987865"; Regex.Replace(sData, @"\d+", delegate(Match oMatch)//delegate is run for each match as closure { char? oLast = null; foreach (char oChar in oMatch.Value)//for each char { if ((oLast != null && Math.Abs(oChar - oLast) > 1))//not in sequense return oMatch.Value;//early return oLast = oChar; } oMatches.Add(oMatch)//add to outside collection return oMatch.Value; //return match itself because we don't actually want to replace anything }); 

Je IsSequential une fonction IsSequential :

 static bool IsSequential(ssortingng input) { var nums = input.Select(Convert.ToInt32); int last = nums.First(); foreach (var num in nums.Skip(1)) { if (num < last) return false; last = num; } return true; } 

il suffit ensuite de vérifier si chaque nombre est IsSequential ou s'il est inversé.

 var inputs = @"123, 234567, 0123456789, 87654, 321, 7891011, 1234566789, 987865"; var valids = inputs .Split(',') .Select(n => n.Trim()) .Where(n => IsIncreasing(n) || IsIncreasing(new ssortingng(n.Reverse().ToArray()))) .ToList(); 

si vous souhaitez qu’ils augmentent exactement de 1, utilisez if(num != last+1)