Regex semplice più breve che corrisponde a una parola binaria


20

Compito

Definire una regex semplice come espressione regolare non vuota composta solo da

  • personaggi 0e 1,
  • raggruppamento di parentesi (e ),
  • uno o più quantificatori di ripetizione +.

Data una stringa non vuota di 0s e 1s, il programma dovrebbe trovare la regex semplice più breve corrispondente alla stringa di input completa . (Cioè, quando abbini una semplice regex, fai finta che sia prenotata da ^ e  $.) Se ci sono più regex più brevi, stampane una o tutte.)

, quindi vince l'invio più breve (in byte).

Casi 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
Dovresti chiarire che vuoi che scriviamo un programma che scrive la regex, non scrivere noi stessi la regex. Ma questo sembra interessante.
gcampbell,

1
Nel mio test, 01100110è un caso interessante ... un algoritmo ingenuo scriverebbe 01+0+1+0o (0+1+)+0che non sono ottimali.
Neil,

Risposte:


2

Pyth, 20 byte

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

L'esecuzione richiede circa 30 secondi, quindi deve essere eseguita offline.

Spiegazione:

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

Non sono del tutto sicuro che ogni stringa più corta sia una sottosequenza di "() 01+" * 4, ma 4 può essere aumentata a 9 senza alcun costo in byte se necessario.


9

JavaScript (ES6), 488 341 byte

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]

Spiegazione: Poiché sei regex possono esprimere tutte le possibili parole binarie e i due più lunghi sono lunghi nove caratteri, è sufficiente controllare quelli e tutte le regex più brevi. Un candidato è ovviamente la stringa con "codifica della lunghezza della corsa" (cioè tutte le corse di cifre sostituite con le +s appropriate ), ma anche le stringhe con una serie di ()s devono essere verificate. Genero 1596 di queste regex (questo include duplicati e regex inutili ma verranno eliminati) e testerò tutti i 1597 per vedere qual è la corrispondenza più breve. Le regex generate si dividono in due tipi: \(\d{2,5}\)\+(60 regex) e (\d\+?)?\(\d[\d+]?(\d[\d+]?)?\)(\d\+?)?(1536 regex mentre evito di generare regex sia con le cifre iniziali che finali).


@LeakyNun Inizialmente pensavo ci fossero 4 regex di lunghezza 9 ma questo è ovviamente errato, quindi ho chiarito la mia spiegazione.
Neil,

2

Pyth - 31 30 29 byte

Forza bruta! Probabilmente può golf un po 'l'iteratore.

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

Test Suite .


1

Rubino, 109 byte

È l'approccio noioso della forza bruta. Funziona perché nessun regex deve mai essere più lungo di 9 caratteri (come nota Neil) e nessun singolo personaggio deve essere ripetuto più di 4 volte (provarlo con la '01()+'.chars*9mia CPU infelice).

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 byte

Sto studiando se esiste un approccio a questo problema oltre alla forza bruta, ma per ora ecco una soluzione di forza bruta Python.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.