Jeśli dopiero mówić o wyrażeniach regularnych z teoretycznego punktu widzenia, są te trzy konstrukcje:
ab # concatenation
a|b # alternation
a* # repetition or Kleene closure
Co można następnie po prostu zrobić:
- utworzyć regułę
S -> (fullRegex)
- za każdy powtarzający się termin
(x)*
w fullRegex
utwórz regułę X -> x X
i X -> ε
, a następnie zamień (x)*
na X
.
- dla każdego naprzemiennie
(a|b|c)
tworzyć reguły Y -> a
, Y -> b
i Y -> c
, a następnie zastąpić (a|b|c)
z Y
Wystarczy powtórzyć to rekurencyjnie (zauważ, że wszystkie x,
a
, b
i c
wciąż może być złożone wyrażenia regularne). Pamiętaj, że do każdego kroku musisz użyć unikalnych identyfikatorów.
To powinno wystarczyć. To z pewnością nie zapewni najbardziej eleganckiej i wydajnej gramatyki, ale na tym polega normalizacja (i powinno się to zrobić w oddzielnym kroku i do tego jest well-defined steps).
Jeden przykład: a(b|cd*(e|f)*)*
S -> a(b|cd*(e|f)*)*
S -> a X1; X1 -> (b|cd*(e|f)*) X1; X1 -> ε
S -> a X1; X1 -> Y1 X1; X1 -> ε; Y1 -> b; Y1 -> cd*(e|f)*
S -> a X1; X1 -> Y1 X1; X1 -> ε; Y1 -> b; Y1 -> c X2 (e|f)*; X2 -> d X2; X2 -> ε
... and a few more of those steps, until you end up with:
S -> a X1
X1 -> Y1 X1
X1 -> ε
Y1 -> b
Y1 -> c X2 X3
X2 -> d X2
X2 -> ε
X3 -> Y2 X3
X3 -> ε
Y2 -> e
Y2 -> f
Mam nadzieję, że żartujesz kiedy pytają nas przez cały obrys dla algorytmu. Jak mogliście zauważyć, byłoby to dużo pracy. Jeśli masz konkretne pytanie dotyczące konkretnego problemu, możesz poprosić o nie, ale nie proście nas o praktyczne zaprojektowanie kodu. – Jasper
Nie powinien być twoim Cfg 'S -> a S; S -> b S; S -> epsilon'? Myślę, że jedynym ciągiem, który zapewniłby ci twój dostarczony cfg, jest "", ponieważ żaden inny ciąg, który akceptuje, nie jest skończony. – Wug
To też naprawdę zależy od elementów składni regex, na które chcesz zezwolić? Tylko regex w sensie teoretycznym? Lub regex w rozszerzonym znaczeniu, w jakim jest on używany w większości silników? –