バイナリワードに一致する最短の単純な正規表現


20

仕事

単純な正規表現を、次のみで構成される空でない正規表現として定義します

  • 文字01
  • 括弧をグループ化(して)
  • 1つ以上の反復量指定子+

0sと1sの空でない文字列が与えられると、プログラムは完全な入力文字列に一致する最短の単純な正規表現を見つけるはずです。(つまり、単純な正規表現に一致する場合、とで予約されているふり^ をし  $ます。)最短の正規表現が複数ある場合は、それらの一部またはすべてを出力します。)

なので、最短の送信(バイト単位)が勝ちます。

テストケース

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
正規表現を自分で作成するのではなく、正規表現を作成するプログラムを作成することを希望することを明確にする必要があります。しかし、これは面白そうです。
gcampbell

1
私のテストで01100110は、興味深いケースです...ナイーブアルゴリズムが書き込む01+0+1+0(0+1+)+0、最適ではありません。
ニール

回答:


2

Pyth、20バイト

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

これを実行するには約30秒かかるため、オフラインで実行する必要があります。

説明:

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

すべての最短文字列が「()01 +」* 4のサブシーケンスであることは完全にはわかりませんが、必要に応じてバイトコストなしで4を9に増やすことができます。


9

JavaScript(ES6)、488 341バイト

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]

説明:6つの正規表現はすべての可能なバイナリワードを表現でき、最長の2つは9文字の長さなので、それらとすべての短い正規表現をチェックするだけで十分です。1つの候補は、「ランレングスエンコーディング」(つまり、すべての数字のランが適切な+sに置き換えられる)を持つ文字列ですが、1組の()sを持つ文字列もチェックする必要があります。このような正規表現を生成し(重複と無用な正規表現が含まれますが、それらは単に除去されます)、すべての1597をテストして、どちらが最短一致であるかを確認します。生成された正規表現は、\(\d{2,5}\)\+(60個の正規表現)と(\d\+?)?\(\d[\d+]?(\d[\d+]?)?\)(\d\+?)?(先頭と末尾の両方の数字を持つ正規表現の生成を避けるため、1536 個の正規表現)の2つのタイプに分類されます。


@LeakyNun元々、長さ9の正規表現が4つあると思っていましたが、これは明らかに間違っているので、説明を明確にしました。
ニール


1

ルビー、109バイト

それは退屈なブルートフォースアプローチです。(Neilが指摘しているように)正規表現が9文字を超える必要はなく、個々の文字を4回以上繰り返す必要がない('01()+'.chars*9CPUが不満になった状態で試してみてください)ため、動作します。

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バイト

総当たり攻撃以外にこの問題へのアプローチがあるかどうかを調査していますが、今のところ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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.