2016-08-17 14 views

Odpowiedz

4

Nie jestem pewien, czy to zachowanie jest udokumentowana lub nie (jeśli tak, to ja nie go znaleźć), ale stosując konstrukcję warunkową tym wyraźny zerowej szerokości twierdzenie jako jego wyrażenie (?(?=expression)yes|no) zastępuje grupę przechwytującą następnej numerowanej (opróżnia ją). Można to potwierdzić poprzez uruchomienie poniżej RegEx:

a(?(?<!))b (c)() 

cztery sposoby rozwiązania tego problemu:

  1. załączając wyraz w nawiasach odnotowanych przez @DmitryEgorov (które również utrzymuje drugą przechwytywania grupę nienaruszony) i nie jest wliczone w rezultacie - prawo sposób:

    a(?((?<!)))b (c) 
    
  2. Jak to zachowanie jest stosowana tylko do nienazwanych grup przechwytywania (domyślnie) można uzyskać oczekiwany wynik stosując nazwie grupy przechwytywania:

    a(?(?<!))b (?<first>c) 
    
  3. dodanie dodatkowej grupy przechwytywania gdziekolwiek chcesz między (c) i warunkowy:

    a(?(?<!))(b) (c) 
    
  4. Unikanie takiego wyrażenia jeśli to możliwe. Np:

    a(?())b (c) 
    
+0

DOTYCZĄCE 'a b (c)', trzeba pamiętać, że ' (?()) 'jest równe' (? (? =)) ', a nie' (? (?

+0

Tak, dodano poprawną frazę. @ WiktorStribiżew – revo

+2

Innym sposobem obejścia tego problemu jest zamknięcie warunku w dodatkowej grupie przechwytującej: 'a (? ((?

2

Oprócz @ Revo answer: nie tylko warunkowego konstruktu

z wyraźnym zerowej szerokości twierdzenia jako jego wypowiedzi są naruszone. W rzeczywistości dotyczy to prawie wszystkich konstruktów warunkowych, w których wyrażenia warunkowe są wyokrąglane regexy (grupowanie, warunkowe, inne specjalne) używane bez dodatkowego nawiasu.

Istnieją cztery rodzaje (MIS) zachowania w takich przypadkach: grupa tablica

  1. przechwytywania zostaje zniekształcone (jak wskazano przez OP), a mianowicie grupa przechwytywania bezpośrednio po konstrukt warunkowego jest stracone pozostałe grupy są przesunięte w lewo, pozostawiając niezdefiniowaną ostatnią grupę przechwytywania.

    W poniższych przykładach oczekiwany przydział przechwytywania

    $1="a", $2="b", $3="c" 
    

    natomiast rzeczywisty wynik jest

    $1="a", $2="c", $3="" (the latter is empty string) 
    

    Dotyczy:

  2. Zgłasza ArgumentException w czasie wykonywania, gdy regex jest analizowany. Ma to sens, ponieważ wyraźnie ostrzega nas przed potencjalnym błędem regularnego użycia, zamiast grać zabawne sztuczki z chwytaniem, jak w poprzednim przypadku.

    Dotyczy:

    • (a)(?(?<n>.))(b) (c), (a)(?(?'n'.))(b) (c) - Komunikat wyjątku - nazwanych grup: "Alternation conditions do not capture and cannot be named"
    • (a)(?(?'-n' .))(b) (c), (?<a>a)(?(?<a-n>.))(b) (c) - grupy bilansujące - Komunikat wyjątku: "Alternation conditions do not capture and cannot be named"
    • (a)(?(?# comment))(b) (c) - inline komentarz - Komunikat wyjątku: "Alternation conditions cannot be comments"
  3. Zgłasza OutOfMemoryException podczas dopasowywania wzorca. To jest oczywiście błąd, jak sądzę.

    Dotyczy:

    • (a)(?(?i))(b) (c) - opcji inline (nie mylić z opcji grupowych)
  4. [Zaskakująco] działa zgodnie z oczekiwaniami, ale jest to raczej zbyt sztuczny przykład:

Wszystkie powyższe wyrażenia można ustalić, zamykając wyrażenie warunku na jawny nawias (tj. dodatkowe, jeśli samo wyrażenie zawiera już nawiasy). Oto trwałe wersje (w kolejności występowania): Kod

(a)(?((?=.)))(b) (c) 
(a)(?((?!z)))(b) (c) 
(a)(?((?<=.)))(b) (c) 
(a)(?((?<!)))(b) (c) 
(a)(?((?:)))(b) (c) 
(a)(?((?i:.)))(b) (c) 
(a)(?((?>.)))(b) (c) 
(a)(?((?(1).)))(b) (c) 
((?<n>a))(?((?(n).)))(b)(c) 
(a)(?((?(?:.).)))(b) (c) 
(a)(?((?<n>.)))(b) (c) 
(a)(?((?'n'.)))(b) (c) 
(a)(?((?'-n' .)))(b) (c) 
(?<a>a)(?((?<a-n>.)))(b) (c) 
(a)(?((?# comment)))(b) (c) 
(a)(?((?i)))(b) (c) 
(a)(?((?(.).)))(b) (c) 

próbki, aby sprawdzić wszystkie te wyrażenia: (?()) https://ideone.com/KHbqMI

+0

Dobra eksploracja. – revo