Kürzester einfacher regulärer Ausdruck, der einem binären Wort entspricht


20

Aufgabe

Definieren Sie einen einfachen regulären Ausdruck als einen nicht leeren regulären Ausdruck, der nur aus besteht

  • Zeichen 0und 1,
  • Gruppierungs Klammern (und ),
  • ein oder mehrere Wiederholungsquantifizierer +.

Bei einer nicht leeren Zeichenfolge von 0s und 1s sollte Ihr Programm den kürzesten einfachen regulären Ausdruck finden, der mit der vollständigen Eingabezeichenfolge übereinstimmt . (Wenn Sie also einen einfachen regulären Ausdruck zuordnen, tun Sie so, als wäre er mit ^ und  verbucht $.) Wenn es mehrere kürzeste reguläre Ausdrücke gibt, drucken Sie einen oder alle aus.)

, so dass die kürzeste Einreichung (in Bytes) gewinnt.

Testfälle

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
Sie sollten klarstellen, dass wir ein Programm schreiben sollen, das den regulären Ausdruck schreibt, und nicht den regulären Ausdruck selbst. Das sieht aber interessant aus.
Gcampbell

1
In meinen Tests 01100110ist ein interessanter Fall ... ein naiver Algorithmus würde schreiben 01+0+1+0oder (0+1+)+0welche sind nicht optimal.
Neil

Antworten:


2

Pyth, 20 Bytes

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

Die Ausführung dauert ungefähr 30 Sekunden, daher muss sie offline ausgeführt werden.

Erläuterung:

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

Ich bin mir nicht ganz sicher, ob jede kürzeste Zeichenfolge eine Untersequenz von "() 01+" * 4 ist, aber 4 kann bei Bedarf ohne Bytekosten auf 9 erhöht werden.


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]

Erläuterung: Da sechs reguläre Ausdrücke alle möglichen binären Wörter ausdrücken können und die längsten zwei neun Zeichen lang sind, ist es ausreichend, diese und alle kürzeren regulären Ausdrücke zu überprüfen. Ein Kandidat ist natürlich der String mit "Lauflängencodierung" (dh alle Ziffernläufe werden durch entsprechende +s ersetzt), aber auch Strings mit einem Satz von ()s müssen überprüft werden. Ich generiere 1596 solcher Regexes (dies schließt Duplikate und nutzlose Regexes ein, aber sie werden einfach eliminiert) und teste alle 1597, um zu sehen, welches die kürzeste Übereinstimmung ist. Die generierten regulären Ausdrücke lassen sich in zwei Typen unterteilen: \(\d{2,5}\)\+(60 reguläre Ausdrücke) und (\d\+?)?\(\d[\d+]?(\d[\d+]?)?\)(\d\+?)?(1536 reguläre Ausdrücke, da ich die Generierung von regulären Ausdrücken mit führenden und nachfolgenden Ziffern vermeide.


@LeakyNun Ursprünglich dachte ich, es gäbe 4 reguläre Ausdrücke mit einer Länge von 9, aber das ist offensichtlich falsch, deshalb habe ich meine Erklärung klargestellt.
Neil

2

Pyth - 31 30 29 Bytes

Rohe Gewalt! Kann den Iterator wahrscheinlich ein wenig Golf spielen.

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

Test Suite .


1

Ruby, 109 Bytes

Es ist der langweilige Brute-Force-Ansatz. Funktioniert, weil kein regulärer Ausdruck länger als 9 Zeichen sein muss (wie Neil bemerkt) und kein einzelnes Zeichen mehr als 4 Mal wiederholt werden muss (wenn '01()+'.chars*9ich es mit meiner CPU probiere , wird meine CPU unglücklich).

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 Bytes

Ich untersuche, ob es für dieses Problem neben dem Brute-Force-Ansatz noch einen Ansatz gibt, aber hier ist eine Python-Brute-Force-Lösung für den Moment.

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.