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.