Regex simple le plus court correspondant à un mot binaire


20

Tâche

Définissez une expression régulière simple comme une expression régulière non vide composée uniquement de

  • personnages 0et 1,
  • regrouper les parenthèses (et ),
  • un ou plusieurs quantificateurs de répétition +.

Étant donné une chaîne non vide de 0s et 1s, votre programme devrait trouver l'expression rationnelle simple la plus courte correspondant à la chaîne d'entrée complète . (C'est-à-dire, lorsque vous associez une expression régulière simple, faites comme si elle était reliée par ^ et  $.) S'il y a plusieurs expressions rationnelles les plus courtes, imprimez-en une ou toutes.)

, donc la soumission la plus courte (en octets) gagne.

Cas de test

1 -> 1
00 -> 00 or 0+
010 -> 010
1110 -> 1+0
01010 -> 01010
0101010 -> 0(10)+ or (01)+0
011111 -> 01+
10110110 -> (1+0)+
01100110 -> (0110)+ or (01+0)+
010010010 -> (010)+
111100111 -> 1+001+ or 1+0+1+
00000101010 -> 0+(10)+ or (0+1)+0
1010110001 -> 1(0+1+)+ or (1+0+)+1

3
Vous devez préciser que vous voulez que nous écrivions un programme qui écrit le regex, et non pas le regex nous-mêmes. Mais cela semble intéressant.
gcampbell

1
Dans mes tests, 01100110c'est un cas intéressant ... un algorithme naïf écrirait 01+0+1+0ou (0+1+)+0qui n'est pas optimal.
Neil

Réponses:


2

Pyth, 20 octets

hf.x}z:zT1Zy*4"()01+

Cela prend environ 30 secondes pour s'exécuter, il doit donc être exécuté hors ligne.

Explication:

hf.x}z:zT1Zy*4"()01+
                        Implicit: z is the input string.
              "()01+    "()01+"
            *4          Repeated 4 times
           y            All subsequences in length order
hf                      Output the first one such that
      :zT1              Form all regex matches of z with the candidate string
    }z                  Check if the input is one of the strings
  .x      Z             Discard errors

Je ne suis pas complètement sûr que chaque chaîne la plus courte soit une sous-séquence de "() 01+" * 4, mais 4 peut être augmenté à 9 sans coût en octets si nécessaire.


9

JavaScript (ES6), 488 341 octets

s=>[s.replace(/(.)\1+/g,'$1+'),...[...Array(60)].map((_,i)=>`(${(i+4).toString(2).slice(1)})+`),...[...Array(1536)].map((_,i)=>`${i>>10?(i>>8&1)+(i&2?'+':''):''}(${i&1}${i&4?i>>4&1:i&16?'+':''}${i&8?''+(i>>7&1)+(i&64?i>>5&1:i&32?'+':''):''})+${i&512?(i>>8&1)+(i&2?'+':''):''}`)].filter(r=>s.match(`^${r}$`)).sort((a,b)=>a.length-b.length)[0]

Explication: Étant donné que six expressions rationnelles peuvent exprimer tous les mots binaires possibles et que les deux plus longs ont neuf caractères, il suffit de les vérifier ainsi que toutes les expressions rationnelles plus courtes. Un candidat est évidemment la chaîne avec "l'encodage de la longueur de la séquence" (c'est-à-dire que toutes les séries de chiffres sont remplacées par des +s appropriés ), mais aussi les chaînes avec un ensemble de ()s doivent être vérifiées. Je génère 1596 telles expressions régulières (cela inclut les doublons et les expressions rationnelles inutiles mais elles seront simplement éliminées) et teste toutes les 1597 pour voir quelle est la correspondance la plus courte. Les expressions régulières générées se répartissent en deux types: \(\d{2,5}\)\+(60 expressions régulières) et (\d\+?)?\(\d[\d+]?(\d[\d+]?)?\)(\d\+?)?(1536 expressions régulières, car j'évite de générer des expressions régulières avec des chiffres à la fois de début et de fin).


@LeakyNun À l'origine, je pensais qu'il y avait 4 expressions régulières de longueur 9, mais cela est évidemment incorrect, j'ai donc clarifié mon explication.
Neil

2

Pyth - 31 30 29 octets

Force brute! Peut probablement jouer un peu à l'itérateur.

 f=+Yf.x:zjY"^$")Z^"10+()"T1Y

Suite de tests .


1

Rubis, 109 octets

C'est l'approche ennuyeuse de la force brute. Fonctionne car aucune expression régulière n'a besoin de plus de 9 caractères (comme le note Neil) et aucun caractère individuel n'a besoin d'être répété plus de 4 fois (l'essayer avec a '01()+'.chars*9rendu mon CPU mécontent).

10.times{|i|('01()+'.chars*4).combination(i).map{|s|begin
/^#{s*''}$/=~$*[0]&&[puts(s*''),exit]
rescue
end}}
$ for word in `grep -Po '^\S+' test_cases.txt`; do nice -n20 ruby sre.rb $word; done
1
0+
010
1+0
01010
0(10)+
01+
(1+0)+
(01+0)+
(010)+
1+0+1+
0+(10)+
1(0+1+)+

1

Python 3, 186 octets

J'étudie s'il existe une approche à ce problème en plus du forçage brutal, mais voici une solution de force brute Python pour l'instant.

import re,itertools
def a(b):
 for z in range(10):
  for i in itertools.combinations("01()+"*4,z):
   j=''.join(i)
   try:
    if re.fullmatch(j,b)and len(j)<=len(b):return j
   except:1
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.