2015-09-23 8 views
5

Próbuję zagłębić się w wyrażenia regularne i chcę dopasować warunek, chyba że niektóre podciągi również znajdują się w tym samym ciągu. Wiem, że mogę użyć dwóch oświadczeń grepl (jak widać poniżej), ale chcę użyć pojedynczego wyrażenia regularnego, aby przetestować ten warunek, ponieważ naciskam na moje zrozumienie. Powiedzmy, że chcę dopasować słowa "pies" i "człowiek" przy użyciu "(dog.*man|man.*dog)" (taken from here), ale nie, jeśli ciąg zawiera podłańcuch "park". Pomyślałem, że mogę użyć (*SKIP)(*FAIL), aby zanegować "park", ale nie spowoduje to niepowodzenia łańcucha (pokazanego poniżej).Wykonywanie podobieńców dopasowań podciąć, chyba że inny podciąg pasuje do

  • jaki sposób można dopasować logikę znaleźć „pies” & „człowiek”, ale nie „park” z 1 regex?
  • Co jest nie tak z moim zrozumieniem (*SKIP)(*FAIL)|?

Kod:

x <- c(
    "The dog and the man play in the park.", 
    "The man plays with the dog.", 
    "That is the man's hat.", 
    "Man I love that dog!", 
    "I'm dog tired", 
    "The dog park is no place for man.", 
    "Park next to this dog's man." 
) 

# Could do this but want one regex 
grepl("(dog.*man|man.*dog)", x, ignore.case=TRUE) & !grepl("park", x, ignore.case=TRUE) 

# Thought this would work, it does not 
grepl("park(*SKIP)(*FAIL)|(dog.*man|man.*dog)", x, ignore.case=TRUE, perl=TRUE) 

Odpowiedz

6

Można użyć zakotwiczonej rozwiązanie antycypowanego (wymagającą Perl stylu regexp):

grepl("^(?!.*park)(?=.*dog.*man|.*man.*dog)", x, ignore.case=TRUE, perl=T) 

Oto IDEONE demo

  • ^ - zakotwicza wzór w początek napisu
  • (?!.*park) - fail meczu jeśli park występuje
  • (?=.*dog.*man|.*man.*dog) - fail meczu jeśli man i dog są nieobecne.

Inna wersja (więcej skalowania) z 3 przeglądowej aheads:

^(?!.*park)(?=.*dog)(?=.*man) 
+0

Nicea Myślałam z jakiegoś powodu nie można wykorzystać kwantyfikator wewnątrz lokaround. –

+2

Możesz użyć kwantyfikatora wewnątrz z wyprzedzeniem, ale nie możesz użyć kwantyfikatora wewnątrz obszaru PCRE.Kwantyfikator może być użyty w funkcji NET look behind i tylko ograniczający kwantyfikator z wartościami minimalnymi i maksymalnymi może być użyty w Java Javy z ograniczoną szerokością. –

3

stribizhev już answered this question jak powinno to być traktowane: ujemnym uprzedzona.

będę przyczynić się do tego konkretnego pytania:

Co jest nie tak z moim rozumieniem (*SKIP)(*FAIL)?

(*SKIP) i (*FAIL) są regex czasowniki kontroli.

  1. (*FAIL) lub (*F)
    Jest to najłatwiejszy do zrozumienia. (*FAIL) to dokładnie taki sam jak negatywny uprzedzający z pustym podpunktem: (?!). Jak tylko silnik regex dojdzie do tego czasownika we wzorcu, wymusza natychmiastowy zwrot.
  2. (*SKIP) Gdy silnik regex pierwszy napotyka ten czasownik, nic się nie dzieje, ponieważ działa tylko kiedy to osiągnięto wycofywania. Ale jeśli wystąpi późniejsza awaria i osiągnie (*SKIP) od prawej do lewej, backtracking nie może przejść (*SKIP). Powoduje:

    • Błąd dopasowania.
    • Następnego meczu nie będzie można próbować od następnego znaku. Zamiast tego rozpocznie się od pozycji w tekście, w którym znajdował się silnik, gdy dotarł do (*SKIP).

    Dlatego te dwa czasowniki kontrolne są zwykle razem jako (*SKIP)(*FAIL)

Rozważmy następujący example:

  • Wzór: .*park(*SKIP)(*FAIL)|.*dog
  • Temat: "That park has too many dogs"
  • Dopasowania : " has too many dog"

Wewnętrzne:

  1. pierwszej próbie.
That park has too many dogs    || .*park(*SKIP)(*FAIL)|.*dog 
      /\          /\ 
      (here) we have a match for park 
       the engine passes (*SKIP) -no action 
       it then encounters (*FAIL) -backtrack 
       Now it reaches (*SKIP) from the right -FAIL! 
  1. druga próba.
    Normalnie powinien zaczynać się od drugiego znaku w temacie. Jednak to szczególne zachowanie ma postać (*SKIP). 2. próba zaczyna:
That park has too many dogs    || .*park(*SKIP)(*FAIL)|.*dog 
      /\              /\ 
      (here) 
      Now, there's no match for .*park 
      And off course it matches .*dog 

    That park has too many dogs    || .*park(*SKIP)(*FAIL)|.*dog 
      ^   ^          ----- 
      | (MATCH!) | 
      +---------------+ 

DEMO


jaki sposób można dopasować logikę znaleźć "pies" & "człowiek", ale nie "park" z 1 regex?

Użyj rozwiązania stribizheva! Staraj się unikać używania czasowników kontrolnych ze względu na kompatybilność, nie są one implementowane we wszystkich smakach regex. Ale jeśli interesujesz się tymi dziwactwami regularnymi, istnieje inny, silniejszy czasownik kontrolny: (*COMMIT). Jest podobny do (*SKIP), działa tylko podczas cofania, ale powoduje, że cały mecz kończy się niepowodzeniem (w ogóle nie będzie żadnych innych prób). Dla example:

+-----------------------------------------------+ 
|Pattern:          | 
|^.*park(*COMMIT)(*FAIL)|dog     | 
+-------------------------------------+---------+ 
|Subject        | Matches | 
+-----------------------------------------------+ 
|The dog and the man play in the park.| FALSE | 
|Man I love that dog!     | TRUE | 
|I'm dog tired      | TRUE | 
|The dog park is no place for man. | FALSE | 
|park next to this dog's man.   | FALSE | 
+-------------------------------------+---------+ 

IDEONE demo

Powiązane problemy