kiedy używać wyrażeń regularnych

0

Zauważyłem że wiele osób tu mówi o jakimś parsowaniu, gdy ja, zaczarowany potęgą wyrażeń regularnych, używam ich do przeróżnych celów. I w związku z tym małe pytanie: jak zabrać się za te parsery bo w sumie to wyrażeń regularnych używałem już do takich niechlubnych czynności, które pewnie mogłby by być dużo prostsze jak:

  • pobieranie z pliku tekstowego jakiś danych
  • ostatnio piszę klienta irc i gdy chcę coś zrobić z otrzymanymi danymi to właśnie się męczę z wyrażeniami regularnymi np.
    ":(?<cnick>\S+)!.+PRIVMSG\s(?<to>\S+)\s:(?<tekst>.+)"
    dla przykładowego tekstu
    ":ubuntuser!~[email protected] PRIVMSG #channeltest :lalala"
    lub bardziej porąbane ustawianie kolorków
    "(\x03(?<fore>\d+),(?<back>\d+))|(\x03(?<fore>\d+))|(?<end1>\x03)|(?<end2>\x0F)"
    "4,5<ubuntuser>test"

No i pytanie czy w w/w przypadkach wyrażenia regularne są dobrym pomysłem a jesli nie to jak takie rzeczy zalatwiać

1

Cóż, pojadę teorią: wyrażenia regularne służą do rozpoznawania (parsowania) języków regularnych. Dla bardziej skomplikowanych języków (bezkontekstowych, kontekstowych, rekurencyjnych, rekurencyjnie przeliczalnych) się nie nadaje. Już chociażby parsowanie XML nie może być załatwione przez wyrażenie regularne ze względu na zagnieżdżanie się węzłów. Więcej poczytaj tutaj, bo teoria języków formalnych jest doprawdy ogromna, dość trudna i w sumie fascynująca. :)

Przykłady regexpów, które przedstawiłeś, są zastosowane właściwie, i nie są w sumie skomplikowane. Weź dla porównania wyrażenie do sprawdzania poprawności adresu e-mail według RFC-2822. :D
(?:[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

0

ostatnio piszę klienta irc i gdy chcę coś zrobić z otrzymanymi danymi to właśnie się męczę z wyrażeniami regularnymi

W moim bocie IRC jest to dzielone według spacji, jest to generalnie dobre rozwiązanie. Wszystko mam w jednej procedurze która wykrywa polecenie, użytkownika itd. Potem leci to na rozpoznawanie parametrów a następnie już do poleceń odpowiadających na PRIVMSG, PING czy bóg wie co jeszcze. To rozwiązanie sprawdza się.
Regexpów (mojej konstrukcji - uważam inne za mało czytelne) używam w moim języku skryptów który odpowiada za kontrolowanie bota i pisanie do niego instrukcji...

0

No i pytanie czy w w/w przypadkach wyrażenia regularne są dobrym pomysłem a jesli nie to jak takie rzeczy zalatwiać
jeśli całe wyrażenie ma więcej niż powiedzmy 10 znaków, to jest to zły pomysł, bo szybko zapomnisz o co w nim chodziło, nie mówiąc już o tym, że kod w którym są używane jest kompletnie niezrozumiały dla osób, które regexpów nie zgłębiły.

0

Ok, ale co zamiast tego? no bo wyrażenie regularne jest szybkie, ma grupy, ale nie zawsze mi pasuje. Np pisze sobie że ma być \S+ a potem np \x03 a Regex potrafi potraktować znaczek \x03 jako \S jeśli w tekście jest np dwa razy \x03, to on zaznacza wtedy to ostatnie.
Ogólnie potrzebuje czegoś takiego, co by obsłużyło znak rozpoczynający i znak zamykający, wśród których może być znowu znak rozpoczynający i znak zakańczający. Any ideas?
Mam na myśli np coś takiego:
"4,5<ubun7tuser>test"
"" i ("" lub "") wyznacza odpowiednio początek i koniec jakiegoś kolorku (w w/w przykladzie 4,5) natomiast w środku mogą się zdażyć inne zagnieżdzone kolorki.

1

To wskazuje na to, że potrzebujesz parsować wyrażenia języka bezkontekstowego (problem nawiasowania). W takim wypadku poleciłbym jakiś parser LL albo LR, ale dla tak prostych przypadków wystarczy Ci wykorzystać stos jadąc znak po znaku: po napotkaniu znaku rozpoczynającego kolor, wrzucasz dany kolor na stos, a po napotkaniu znaku kończącego kolor -- zdejmujesz. Aktualnym kolorem jest ten z wierzchołka stosu.

0
ubuntuser napisał(a)

Ok, ale co zamiast tego? no bo wyrażenie regularne jest szybkie, ma grupy, ale nie zawsze mi pasuje. Np pisze sobie że ma być \S+ a potem np \x03 a Regex potrafi potraktować znaczek \x03 jako \S jeśli w tekście jest np dwa razy \x03, to on zaznacza wtedy to ostatnie.
Nie wiem, czy zrozumiałem, ale w regexach jest rozróżnienie na lazy (\S+?), greedy (\S+) i possessive (\S++) quantifiers.

0
iooi napisał(a)

Nie wiem, czy zrozumiałem, ale w regexach jest rozróżnienie na lazy (\S+?), greedy (\S+) i possessive (\S++) quantifiers.

Owszem, jednak w opisanym przypadku kolorów żadne z nich się nie sprawdzą. Weźmy na przykład nawiasowanie:

( ( ) ( ) ) ( )
Regex:
\(.*\) // greedy
Match: ( ( ) ( ) ) ( ) // nieprawidlowo, nawiasy niesparowane
\(.*?\) // lazy
Match: ( ( ) // nieprawidlowo, nawiasy niesparowane
0

Any ideas?
W tak prostych przypadkach najlepszym rozwiązaniem jest parser ad hoc, czyli ładnie po polsku: na pałę.

0

Do parsowania HTML'a w PHP np. jest simple html dom parser - http://simplehtmldom.sourceforge.net/

Poczytaj kod, może coś Ci się rozjaśni :)

0

Ogarnąłem to i działa jak należy, ale troche trzeba bylo się napierdzielić.
Zrobiłem sobie stosik jak mówił @rincewind

Stack<Kolorek> otwarte = new Stack<Kolorek>();

No i doszlifowałem wyrażenie i obsługę - kolorki prezentują się jak należy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1