Pomóżcie z regexem bo nie mogę tego ogarnąć :/

0

Otóż mam dany ciąg : " jakis tekst ' pies koń ' krowa' fdsfsdf "

teraz za pomoca regexa chcę wyodrębnić dokładnie: 'pies koń ' krowa'

Gdyby nie ' bylo by prosto:

1.znajdz znak '
2.znajdz inny niz '

Myślę więc dalej tak :

1.znajdz znak apostrof(')
2.znajdz inny niz ( inny niz backslash() i apostrof(') )

problem z takim rozwiazaniem jest taki że ucina ostatnia litere czyli a od krowa poniewaz to jest inny niz backslash i konczy sie na apostrofie .

Chce to zrobić za pomocą jednego podejścia - to dla mnie ważne. Jak by ktoś potrafił to niech rozpisze tak jak ja to rozpisałem będzie mi łatwiej zrozumieć.

0

Może: /'.?*(?<!)'/
Sprawdziłbym czy to działa, ale niestety sprzęt nie pozwala mi uruchomić VS obok NetBeansa ;)

0

Ale mógłbyś to rozdzielić na cyfry abym zrozumiał jak to działa ? Też chwilowo nie mogę sprawdzić czy działa.

0

Mi się też nie chce tego sprawdzić, ale z tego co widzę to jest tam błąd. W pobliżu początku masz tam ".?". Domyślam się, że z tym znakiem zapytania chodziło o wyłączenie zachłanności operatora . W takim wypadku jednak znak zapytania stawiamy ZA, a nie przed operatorem. Czyli nie ".?", tylko ".?".

Kod jest bardzo prosty, używa czegoś, co się po angielsku zwie "negative lookbehind". Tym lookbehindem jest ciąg "(?<!)". Lookbehindy (te negatywne) mają postać "(?<!WYRAŻENIE)". Lookbehind normalnie nie jest dopasowany. Dopiero gdy zostanie dopasowane coś za lookbehindem, to wtedy sprawdzane jest, czy lookbehind jest spełniony. Ten negatywny jest spełniony, jeśli za bieżącym znakiem nie znajduje się WYRAŻENIE.

Więc w sumie działa to tak, rozbijając na części całe wyrażenie (zauważ, że znaki "/" to tylko ograniczniki początku/końca wyrażenia regularnego; w JavaScripcie się je normalnie wpisuje, w PHP też można, nie pamiętam jak jest w C# -- tutaj pominę te ograniczniki):

'.*?(?<!)'

Dopasuj apostrof. To początek stringu. A dalej....

'.*?(?<!)'

Dopasuj dowolną liczbę dowolnych znaków, ALE...

.*?(?<!)'

...ale dopasuj ich najmniej jak się da. To dzięki wyłączeniu zachłanności operatora *. Gdyby zachłanność ta nie została wyłączona, to operator * połączony ze zjadaczem wszystkich znaków (kropką) zjadłby wszystkie znaki podane na wejściu, łącznie z apostrofem kończącym ciąg. A apostrofów na razie nie jemy!

Idziemy dalej:

.*?(?<!)'

To jest lookbehind (negatywny). Póki co go olewamy, bo sam w sobie nie dopasowuje. Czeka, aż zostanie dopasowane coś, co znajduje się za nim. A więc dopasowywane jest to, co jest w dalszej części wyrażenia, czyli...

.*?(?<!)'

Apostrof! OK, i to jest koniec ciągu. Ale jeszcze nie możemy uznać, że całe wyrażenie pasuje. Po dopasowaniu apostrofa musimy się cofnąć i uruchomić ten zostawiony na chwilę na boku lookbehind. Czyli to:

.*?(?<!)'

Lookbehind jest negatywny, więc dopasowuje wszystko, tylko nie znak . Ponieważ w poprzednim akapicie dopasowaliśmy apostrof, lookbehind sprawdza, co stoi tuż przed apostrofem. Jeśli coś innego niż znak \ -- to nie ma sprawy, mamy dopasowanie. Jeśli przed apostrofem jest znak , to negatywny lookbehind zgłasza obiekcie. I dopasowania nie ma.

Więc parser leci dalej i szuka kolejnego apostrofa, do którego tym razem mógłby dopasować również lookbehinda. Czyli szuka takiego, który nie jest poprzedzony znakiem .

Tak to wygląda w teorii -- w praktyce nie sprawdzałem :D.

0

Dzięki , wszystko jasne.

0

PS. Skoro ukośnik to znak ucieczki i chcesz być dokładny w parsowaniu danych, to nie zapominaj o takich przypadkach:
'aaa\'
'aaa\'
'aaa\\\\\\\\\\\\\\\\\'

Moja propozycja to:
@"'((?:[^\\']+|\\\\|\\.)*)'"

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