Regexes'i Derle


17

Bu görevde, normal bir ifadeyi okuyan ve bir giriş dizesinin bu normal ifade tarafından kabul edilip edilmediğini çıkaran başka bir program oluşturan bir program yazmanız gerekir. Çıktı, başvurunuzla aynı dilde yazılmış bir program olmalıdır.

Giriş

Girdi, aşağıdaki ABNF ile eşleşen normal bir ifade r'dir (ilk üretim kuralı şöyledir REGEX):

REGEX       = *( STAR / GROUP / LITERAL / ALTERNATIVE )
STAR        = REGEX '*'
GROUP       = '(' REGEX ')'
LITERAL     = ALPHA / DIGIT
ALTERNATIVE = REGEX '|' REGEX

Giriş bu dilbilgisi ile eşleşmiyorsa, programınızın davranışı tanımlanmamıştır.

yorumlama

Girişi düzenli bir ifade olarak yorumlayın, burada *Kleene-yıldızı (yani sol argümanı sıfır veya daha fazla kez tekrarlayın ), |bir alternatiftir (ve )gruptur ve hiçbir operatör birleştirilmez. Gruplama yıldızdan önce, yıldız birleştirme yerine, birleştirme ise alternatiften önceliklidir.

Normal ifadenin tüm dizeyle eşleşmesi durumunda bir dizenin kabul edildiği söylenir .

Çıktı

Programın çıkış bir dize okur Gönderiminizde aynı dilde yazılmış bir başka programdır ın zamanında bir uygulama tanımlı bir şekilde, ister çıkışlar r kabul s sonra ve sona erer. Çıktı, kullanıcı tanımlı bir şekilde yapılabilir, ancak kabul edilen ve reddedilen programlar için yalnızca iki ayrı çıktı olmalıdır.

Çıktı programınızın girişinin asla 2 16 -1 Bayttan uzun olmadığını varsayabilirsiniz .

Kısıtlamalar

Ne gönderiminiz ne de gönderiminiz tarafından oluşturulan herhangi bir program yerleşik işlevleri veya kütüphaneleri kullanamaz.

  • normal ifadelerle eşleş
  • düzenli ifadeleri dönüştürmek
  • düzenli ifadeleri derler
  • dilbilgisinden ayrıştırıcılar oluşturmak
  • problemi gönderiminiz önemsiz olacak şekilde basitleştirin

puanlama

Gönderdiğiniz puan, karakter sayısıdır. En düşük puana sahip sunum kazanır.

testcases

Tüm test senaryoları, düzenli bir ifade, bir dizi kabul edilen dizeler, bir dizi reddedilen diziler ve C99'da (hiptothetik) C99 gönderiminin geçerli bir çıktısı olan bir örnek program içerir.

(boş normal ifade)

Kabul edilen dizeler

  1. (boş giriş)

Reddedilen dizeler

  1. foo
  2. bar
  3. baz
  4. quux

Örnek program

#include <stdio.h>

int main() {
    char input[65536];
    gets(input);

    return input[0] != 0;
}

(b|)(ab)*(a|)( ave bdönüşümlü olarak)

kabul edilen dizeler

  1. a
  2. ba
  3. abababababa
  4. abab

reddedilen dizeler

  1. afba
  2. foo
  3. babba

örnek program

#include <stdio.h>

int main() {
  char input[65536];
  int state = 0;

  for (;;) switch (state) {
    case 0: switch (getchar()) {
      case 'a': state = 1; break;
      case 'b': state = 2; break;
      case EOF: return 0;
      default:  return 1;
    } break;
    case 1: switch (getchar()) {
      case 'b': state = 2; break;
      case EOF: return 0;
      default:  return 1;
    } break;
    case 2: switch (getchar()) {
      case 'a': state = 1; break;
      case EOF: return 0;
      default:  return 1;
    } break;
}

(0|1(0|1)*)(|A(0|1)*1) (ikili kayan nokta sayıları)

kabul edilen dizeler

  1. 10110100
  2. 0
  3. 1A00001

reddedilen dizeler

  1. 011
  2. 10 A
  3. 1A00
  4. 100A010

1
Böyle bir programa sahip olmanın return (regex.match(stdin) is not null)yasak olduğunu düşünüyorum.
beary605

1
"Çıktının girdiyle aynı dilde yazılmış bir program olması gerekir", ancak girdinin bir normal ifade olduğunu söylüyorsunuz. Ve sağladığınız dilbilgisi, muhtemelen parantezleri tanımlayan GROUP kuralını içermiyor.
Peter Taylor

@Peter Maalesef gönderimle aynı dili yazmak istedim.
FUZxxl

@ beary605 Evet, haklısın. Bölüm Bkz Kısıtlamaları : gönderiminiz ne de Gönderiminizde tarafından oluşturulan herhangi bir program Ne işlevsellik veya kütüphaneler yerleşik kullanabileceğini maç regexes (...).
FUZxxl

Sanırım ikinci örnek programınız yanlış, dış anahtarın etrafında bir döngü eksik
Hasturkun

Yanıtlar:


8

Yakut, 641 651 543 karakter

H=Hash.new{|h,k|[k]}
d=[[i=0,0,[]]]
o=[?(]
L="t,u,v=d.pop;q,r,s=d.pop;o.pop<?|&&(H[r]<<=t)||(H[q]<<=t;H[r]<<=u);d<<[q,u,s+v]"
gets.chop.chars.map{|c|c==?*&&(q,r,s=d.pop;H[r]|=[q,i+=1];d<<=[r,i,s];next)
eval(L)while/[|)]/=~c ?o[-1]>?(:o[-1]==?.
/[|(]/=~c&&d<<[i+=1,i,o<<c&&[]]||c!=?)&&d<<[i+=1,i+1,["s==#{o<<?.;i}&&c=='#{c}'&&#{i+=1}"]]||o[-1]=?.}
eval(L)while o.size>1
H.map{H.map{|k,v|v.map{|v|H[k]|=H[v]}}}
t,u,v=d[0]
$><<"s=#{H[t]};gets.chop.chars.map{|c|s=s.map{|s|#{v*'||'}}-[!0];#{H.map{|k,v|"s&[#{k}]!=[]&&s|=#{v}"}*?;}};p s&[#{u}]!=[]"

Bu yakut versiyonu regex ayrıştırıcı birkaç köşe vaka nedeniyle oldukça uzun oldu (belki farklı bir yaklaşım denemek gerekir). STDIN'de normal ifadeyi bekler ve eşleştiricinin karşılık gelen yakut kodunu STDOUT'a verir.

Program , daha sonra eşleştiricide yürütülen bir NFA- code için kod üretir .

Test durumu 1: (çıktı ek satırsonu ve girinti içerir)

>>>

s=[0];
gets.chop.chars.map{|c|
  s=s.map{|s|}-[!0];
};
p s&[0]!=[]

Test örneği 2:

>>> (b|)(ab)*(a|)

s=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
gets.chop.chars.map{|c|
  s=s.map{|s|s==2&&c=='b'&&3||s==6&&c=='a'&&7||s==8&&c=='b'&&9||s==12&&c=='a'&&13}-[!0];
  s&[1]!=[]&&s|=[1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[3]!=[]&&s|=[3, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[0]!=[]&&s|=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[5]!=[]&&s|=[5, 6];
  s&[7]!=[]&&s|=[7, 8];
  s&[9]!=[]&&s|=[9, 5, 10, 6, 11, 12, 14];
  s&[4]!=[]&&s|=[4, 9, 5, 10, 6, 11, 12, 14];
  s&[11]!=[]&&s|=[11, 12, 14];
  s&[13]!=[]&&s|=[13, 14];
  s&[10]!=[]&&s|=[10, 11, 12, 14]
};
p s&[14]!=[]

Başka bir örnek:

>>> a|bc

s=[0, 1, 3, 4];
gets.chop.chars.map{|c|
  s=s.map{|s|s==1&&c=='a'&&2||s==4&&c=='b'&&5||s==6&&c=='c'&&7}-[!0];
  s&[0]!=[]&&s|=[0, 1, 3, 4];
  s&[3]!=[]&&s|=[3, 4];
  s&[5]!=[]&&s|=[5, 6];
  s&[2]!=[]&&s|=[2, 7]
};
p s&[7]!=[]

Düzenleme: Lütfen yorumlarda belirtilen hatayı düzeltmek için bir geçiş eklendi . Ayrıca durumun başlatılması değişti.


Normal ifade 011için giriş (0|1(0|1)*)(|A(0|1)*1)sonuçları true- olması gerekir false.
2012'de

@PleaseStand Sabit. Lütfen düzenlememe bakın.
Howard

12

C, 627 karakter

Bu program ilk komut satırı argümanını girdi olarak ele alır ve çıktısı olarak C kodu üretir.

#define A(v) F[v]+strlen(F[v])
#define S sprintf
char*B="&&f%d(s)||f%d(s)",*J="&&f%d(s+%d)",*r,F[256][65536];h=2;e(f,n,o,R,C,O,t,g){for(C=O=f;*r;++r)switch(*r){case 40:r++;e(g=h++,C=h++,0,0);r[1]^42?t=g:(t=C,S(A(t),B,g,C=h++),r++);o=!S(A(O),J,t,o);O=C;break;case 41:goto L;case'|':S(A(C),J,n,o);o=!S(A(O=f),"||1");break;default:r[1]^42?S(A(C),"&&s[%d]==%d",o++,*r,O^f||R++):(o=!S(A(O),J,t=h++,o),O=C=h++,g=h++,S(A(g),"&&*s==%d&&f%d(s+1)",*r++,t),S(A(t),B,g,C));}L:S(A(C),J,n,o);}main(int c,char**v){r=v[1];for(e(1,!S(*F,"&&!*s"),0,0);h--;)printf("f%d(char*s){return 1%s;}",h,F[h]);puts("main(int c,char**v){exit(f1(v[1]));}");}

İşte çıktı (0|1(0|1)*)(|A(0|1)*1)(yeni satırlar eklenmiş olarak):

f11(char*s){return 1&&s[0]==49&&f7(s+1);}
f10(char*s){return 1&&s[0]==48&&f9(s+1)||1&&s[0]==49&&f9(s+1);}
f9(char*s){return 1&&f10(s)||f11(s);}
f8(char*s){return 1&&f7(s+0)||1&&s[0]==65&&f9(s+1);}
f7(char*s){return 1&&f0(s+0);}
f6(char*s){return 1&&f2(s+0);}
f5(char*s){return 1&&s[0]==48&&f4(s+1)||1&&s[0]==49&&f4(s+1);}
f4(char*s){return 1&&f5(s)||f6(s);}
f3(char*s){return 1&&s[0]==48&&f2(s+1)||1&&s[0]==49&&f4(s+1);}
f2(char*s){return 1&&f8(s+0);}
f1(char*s){return 1&&f3(s+0);}
f0(char*s){return 1&&!*s;}
main(int c,char**v){exit(f1(v[1]));}

İlk komut satırı bağımsız değişkeni olarak geçerli bir girdi sağlarsanız, çıkış durumu 1'i döndürür. Aksi takdirde, çıkış durumu 0'ı döndürür.

$ ./regexcompiler '(0 | 1 (0 | 1) *) (| A (0 | 1) * 1)'> floatprog.c
$ gcc -o floatprog floatprog.c
floatprog.c: 'main' işlevinde:
floatprog.c: 1: 519: uyarı: yerleşik 'exit' işlevinin uyumsuz örtülü bildirimi [varsayılan olarak etkindir]
$ ./floatprog '1A00001' && echo geçersiz || echo geçerli
geçerli
$ ./floatprog '100A010' && echo geçersiz || yankı geçerli
geçersiz

Her iki program da, komut satırı bağımsız değişkenini sağlayamazsanız, boş bir işaretçi seçerek bölümleme hatasına neden olur. Yeterince uzun bir normal ifade bu gönderimdeki arabellekleri aşacaktır ve oluşturulan bir programa giriş boyutu yığının boyutu ile sınırlıdır. Ancak, tüm test vakaları işe yarıyor.

e(g=h++,C=h++,0,0);Tanımsız davranış tanıtan not . Örneğin, oluşturulan programlar derlenmezse, ifadeyi h+=2;e(g=h-1,C=h-2,0,0);beş karakter uzunluğunda değiştirmeyi deneyebilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.