Regex pour multiples de 9


14

Il est facile de décrire une machine à états finis qui reconnaît les multiples de 9: gardez une trace de la somme des chiffres (mod 9) et ajoutez le chiffre qui sera accepté ensuite. Un tel FSM n'a que 9 états, très simple! Par l'équivalence entre la reconnaissance des FSM et les langues régulières, il existe une expression régulière pour des multiples de 9. Cependant, une telle expression régulière est probablement ... très ... longue. Comme dans, probablement de l'ordre d'un gigaoctet.

Il y a un exemple travaillé sur https://www.quaxio.com/triple/ pour des multiples de 3. En bas de la page, l'auteur fournit une solution quelque peu "optimisée à la main" qui est un peu plus courte que la conversion naïve de FSM à regex.

Le défi:

Vous devez créer une expression régulière pour détecter des multiples de 9. Puisqu'une telle expression régulière devrait être très longue, je vous demande de fournir un programme capable d'imprimer votre expression régulière. (Si vous voulez vraiment donner un regex entier, peut-être l'héberger ailleurs et le lier ici!)

Vous devez être en mesure de nous dire le nombre exact de caractères de la sortie de votre programme - donc avoir un programme qui essaie simplement toutes les expressions régulières jusqu'à une certaine longueur, jusqu'à ce qu'il en trouve un qui fonctionne, n'est acceptable que s'il s'exécute assez rapidement pour que vous puissiez exécutez-le jusqu'à la fin et donnez-nous la longueur d'expression régulière résultante!

Les points sont destinés à avoir l'expression rationnelle la plus courte, non basée sur la durée du programme, bien sûr. Étant donné que l'expression régulière est le "programme" que je demande, et qu'il est tout simplement trop long pour être transmis ici, je continue de baliser ce code-golf.

Règles:

  • L'entrée comprendra uniquement les caractères correspondants [0-9]*.
  • Votre expression régulière doit correspondre à des multiples de 9, mais pas à autre chose. Les cas qui ne sont pas entièrement composés des chiffres 0 à 9 et qui sont des entrées non valides peuvent correspondre ou échouer comme vous le souhaitez.
  • Étant donné la motivation qu'il est facilement reconnaissable par un DFA, l' expression régulière résultante doit en fait être une expression régulière dans la terminologie plus théorique, c'est-à-dire uniquement les opérateurs sous lesquels les langages réguliers sont fermés. Pour être précis, les seules choses autorisées:
    • Littéraux, les chaînes de caractères ( [ab], [a-f], [^k]), Kleene étoile ( *), points d' ancrage ( ^et $), le regroupement par parenthèses, l' alternance ( |), les termes en option ( ?), un-ou-plus de termes ( +), lookaheads ( (?=)), lookaheads négative ( (?!)), lookbehinds ( (?<=)), lookbehinds négatifs ( (?<!)), conditionnels (comme dans https://www.regular-expressions.info/conditional.html - (?(?=test)then|else)), et références inverses de longueur limitée (voir ci-dessous).
  • Des exemples de choses qui ne sont pas autorisés:
    • Références inverses de longueur arbitraire, références directes, récursivité, sous-programmes, constructions en boucle, code exécutable, toute variation de 'eval' ou constructions intégrées pour convertir la chaîne en une valeur arithmétique.
  • Les références arrières dont on peut montrer qu'elles ont une chaîne de liaison de longueur limitée sont acceptables, car elles peuvent être stockées à l'état fini et ne modifient pas la régularité du langage. Par exemple, l'expression régulière (..2.[3-5])4\1.\1est acceptable, car il y a une longueur liée sur le groupe de capture \1. Il s'agit d'une construction régulière. Une construction telle que (2*)0\1n'est pas acceptable, car le groupe capturé ne peut pas être stocké dans un état fini.
  • Votre expression régulière est libre d'accepter ou de rejeter des entiers avec des zéros non significatifs comme vous le souhaitez. Cependant, la chaîne "0"doit être acceptée.

2
Connexes , je ne sais pas si cela serait considéré comme un doublon
ASCII uniquement

Ah, hmm! J'ai recherché «regex multiple» mais pas «regex divisible». Je suppose que c'est terriblement similaire, oui.
Alex Meiburg

11
Cela n'a pas encore été dit, alors Bienvenue à PPCG et intéressant premier défi! Comme mentionné par un autre utilisateur, il est souvent recommandé, mais pas obligatoire, de publier des propositions de défi dans le bac à sable afin qu'ils puissent obtenir des commentaires, avant de publier sur le site principal. Cependant, il s'agit d'un défi bien pensé et clair, il n'y a donc aucune raison de le déplacer vers le bac à sable. J'espère que vous apprécierez notre communauté!
caird coinheringaahing

Des solutions de moins de 200 kibio sont possibles, donc ce ne sera pas
SI

3
Solution utilisant les extensions .NET:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Neil

Réponses:


3

Haskell , 207 535 202 073 octets

5 462 octets enregistrés en utilisant 0|9plutôt [09]que possible.

digits n
  | x == 0    = "0|9"
  | otherwise = show x
  where x = mod n 9

regex 0 = "[09]*"
regex n = (regex' n (-1) (-1)) ++ "*"

regex' 0 start end = digits (end - start)
regex' n start end = '(':(regex' 0 start end) ++ (concat ['|':(regex' (n-x) (start-x) (-1)) ++ (regex (n-x))
                                                  ++ (regex' (n-x) (-1) (end-x)) | x <- [1..n]]) ++ ")"

main = do
  putStr ("^" ++ (regex 8) ++ "$")

Essayez-le en ligne!

Juste une adaptation rapide de l'expression régulière donnée dans les notes de bas de page de l'article lié pour commencer.

Pastebin de sortie regex , gracieuseté de Herman Lauenstein.

Bien que je n'aie pas été en mesure de tester la regex complète, la modification du programme pour vérifier la divisibilité par 3 donne à la place quelque chose d'exactement équivalent à la regex sur laquelle je me suis basé. De plus, modifier le programme pour vérifier la divisibilité de la somme des chiffres par 4 ou 5 semble également fonctionner sur les nombres sur lesquels je l'ai testé.


Vous pouvez également tester ce que votre méthode donne pour la divisibilité par 2 (devrait être quelque chose comme /even$/) et la divisibilité par 5 (devrait être quelque chose comme /[05]$/). PS: Mentionnez la langue de votre code
Ton Hospel

Voici un pastebin avec la sortie (avec toutes les occurrences de([09]| remplacé par (0|9|pour économiser des milliers d'octets)
Herman L
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.