2010-08-09 11 views
13

Próbuję utworzyć funkcję Python, która może wziąć zwykły angielski opis wyrażenia regularnego i zwrócić wyrażenie regularne do dzwoniącego.Czy potrzebny jest bardziej deklaratywny sposób wyrażania wyrażeń regularnych? :)

Obecnie mam na myśli opis w formacie YAML. Możemy więc zapisać opis jako surową zmienną łańcuchową, która jest przekazywana do tej innej funkcji, a wynik tej funkcji jest przekazywany do modułu "re". Poniżej znajduje się dość uproszczony przykład:

# a(b|c)d+e* 
re1 = """ 
- literal: 'a' 
- one_of: 'b,c' 
- one_or_more_of: 'd' 
- zero_or_more_of: 'e' 
""" 
myre = re.compile(getRegex(re1)) 
myre.search(...) 

itp

nikomu, że coś z tego rodzaju byłoby szerszego zastosowania? Czy znasz już istniejące pakiety, które mogą to zrobić? Jakie są ograniczenia tego podejścia? Czy ktoś myśli, mając deklaratywny ciąg w kodzie, uczyniłby go bardziej możliwym do utrzymania?

+0

Może JSON lub XML? DTD lub XSD może również dobrze opisać strukturę danych. – codymanix

+7

Więc zamiast złożonego wyrażenia zajmującego całą linię zajmie całą stronę :) –

+4

Osoby, które znają wyrażenia regularne, są z nim wygodne, ale dla wszystkich innych wygląda na to, że alfabet zwymiotował. To może być problem, ale nie jestem pewien. W końcu możesz powiedzieć to samo, co języki programowania dla ludzi, którzy programują, a którzy nie. Może być fajnie to zrobić z obiektami i funkcjami instad of string, ale nie jestem pewien, jaki byłby najlepszy sposób implementacji. +1 za innowacje. – psicopoo

Odpowiedz

2

Dla programistów próby zapisu wyrażeń regularnych, które są łatwe aby grokować i utrzymywać, zastanawiam się, czy tego rodzaju podejście oferowałoby wszystko, czego już nie zapewnia re.VERBOSE.

Dla początkujących Twój pomysł może się podobać. Zanim jednak przejdziesz do tej ścieżki, możesz spróbować wyobrazić sobie, jak wyglądałaby składnia deklaratywna dla bardziej skomplikowanych wyrażeń regularnych za pomocą przechwytywania grup, zakotwiczeń, asercji z wyprzedzeniem i tak dalej. Jednym z wyzwań jest to, że możesz skończyć z deklaratywną składnią, która jest równie trudna do zapamiętania jak sam język regex.

Możesz również pomyśleć o alternatywnych sposobach wyrażania opinii. Na przykład pierwszą myślą, która przyszła mi do głowy, było wyrażenie regexu za pomocą funkcji o krótkich, łatwych do zapamiętania nazwach. Na przykład:

from refunc import * 

pattern = Compile(
    'a', 
    Capture(
     Choices('b', 'c'), 
     N_of('d', 1, Infin()), 
     N_of('e', 0, Infin()), 
    ), 
    Look_ahead('foo'), 
) 

Ale kiedy widzę, że w akcji, wygląda mi to na ból. Istnieje wiele aspektów regex, które są dość intuicyjne - na przykład + oznacza "jeden lub więcej". Jedną z opcji jest podejście hybrydowe, pozwalające użytkownikowi mieszać te części regexu, które są już proste z funkcjami dla bardziej ezoterycznych bitów.

pattern = Compile(
    'a', 
    Capture(
     '[bc]', 
     'd+', 
     'e*', 
    ), 
    Look_ahead('foo'), 
) 

Dodam, że w moim doświadczeniu, wyrażenia regularne są o nauce procesu myślowego. Wygoda z składnią jest łatwa.

6

To jest rzeczywiście bardzo podobne (identyczne?) Do działania lexer/parser. Jeśli masz zdefiniowaną gramatykę, prawdopodobnie możesz napisać parser bez większych problemów. Na przykład możesz napisać coś takiego:

<expression> :: == <rule> | <rule> <expression> | <rule> " followed by " <expression> 
<rule>  :: == <val> | <qty> <val> 
<qty>  :: == "literal" | "one" | "one of" | "one or more of" | "zero or more of" 
<val>  :: == "a" | "b" | "c" | "d" | ... | "Z" | 

Nie ma nawet idealnego opisu. Aby uzyskać więcej informacji, zobacz this BNF of the regex language. Następnie można spojrzeć na wyrażenie: lexing i parsing.

Jeśli zrobiłeś to w ten sposób, prawdopodobnie zbliżyłbyś się trochę do Natural Language/Angielskich wersji wyrażeń regularnych.


Widzę przydatne narzędzie, ale jak już wcześniej wspomniano, głównie dla początkujących. Głównym ograniczeniem tego podejścia będzie ilość kodu, który musisz napisać, aby przetłumaczyć język na wyrażenie regularne (i/lub odwrotnie). Z drugiej strony, myślę, że dwukierunkowe narzędzie do tłumaczenia byłoby bardziej idealne i bardziej użyteczne. Możliwość skorzystania z wyrażenia regularnego i przekształcenia go w język angielski może okazać się o wiele bardziej pomocna w wykrywaniu błędów.

Oczywiście nie zajmie to zbyt wiele czasu na wyodrębnienie wyrażenia regularnego, ponieważ składnia jest zwykle zwięzła, a większość znaczeń jest dość wymowna, przynajmniej jeśli używasz | lub || jako OR w twoim języku i myślisz o * jako pomnożenie przez 0-N, + jako dodanie 0-N.

Chociaż czasami nie miałbym nic wpisując „znaleźć jeden lub więcej«a», a następnie trzech cyfr lub«B», a następnie«c»”

+0

W odpowiedzi na pytanie "Możliwość skorzystania z wyrażenia regularnego i jego zmiany na język angielski może być o wiele bardziej pomocna w wykrywaniu błędów", spróbuj Parametr 're.DEBUG' z pytonem w trybie replikacji. – Daenyth

+0

@Denekt - znam ten tryb, chociaż nie miałem powodu go używać i nie mogę powiedzieć, że jest on lepszy niż oryginalne wyrażenie regularne, chyba że jest to bardzo skomplikowane wyrażenie regularne. –

6

Proszę spojrzeć na pyparsing. Wiele problemów opisywanych przez RE to te same, które zainspirowały mnie do napisania tego pakietu.

Oto kilka specyficznych cech pyparografii z rozdziału e-booków O'Reilly "What's so special about pyparsing?".

+1

Pokonałeś mnie o sekundę! BTW, dzięki za pisanie pyparsing :) –

2

może nie dokładnie to, co prosicie, ale istnieje sposób, jak napisać regexes bardziej czytelny sposób (VERBOSE wkrótce X flagę):

rex_name = re.compile(""" 
    [A-Za-z] # first letter 
    [a-z]+  # the rest 
""", re.X) 

rex_name.match('Joe') 
Powiązane problemy