2013-05-16 16 views
16

Ich bin mir ziemlich sicher, dass ich etwas offensichtlich hier fehlt bin, aber ich kann nicht R machen zu verwenden, nicht gierige reguläre Ausdrücke:Nicht gierig String regulären Ausdruck entspricht

> library(stringr) 
> str_match('xxx aaaab yyy', "a.*?b")           
    [,1] 
[1,] "aaaab" 

Basisfunktionen verhalten sich auf die gleiche Weise:

> regexpr('a.*?b', 'xxx aaaab yyy') 
[1] 5 
attr(,"match.length") 
[1] 5 
attr(,"useBytes") 
[1] TRUE 

ich das Spiel erwarten würde nur ab nach 'gierig' Kommentar in http://stat.ethz.ch/R-manual/R-devel/library/base/html/regex.html sein:

Standardmäßig ist die Wiederholung gierig, also wird die maximal mögliche Anzahl von Wiederholungen verwendet. Kann durch Anhängen auf "minimal" geändert werden? zum Quantifizierer. (Es gibt weitere quantifiers die ungefähre Anpassung erlauben: siehe TRE-Dokumentation.)

Könnte mir bitte jemand erklären, was los ist?

Aktualisierung. Was verrückt ist, dass in einigen anderen Fällen nicht gierige Muster wie erwartet verhalten:

> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*>') 
    [,1]           
[1,] "<a href=\"abc\">link</a> yyy <h1>Header</h1>" 
> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*?>') 
    [,1]    
[1,] "<a href=\"abc\">" 

Antwort

18

schwieriges Konzept, damit ich werde mein Bestes versuchen ... Jemand gerne besser bearbeiten und erklären, wenn es ein bisschen verwirrend .

Ausdrücke, die Ihren Mustern entsprechen, werden von links nach rechts durchsucht. Ja, alle folgenden Zeichenfolgen aaaab, aaab, aab und ab sind Übereinstimmungen mit Ihrem Muster, aber aaaab ist diejenige, die am weitesten links beginnt, die zurückgegeben wird.

Also hier ist Ihr nicht-gieriges Muster nicht sehr nützlich. Vielleicht wird dies ein weiteres Beispiel helfen, besser zu verstehen, wenn ein nicht-gierigen Muster anspringt:

str_match('xxx aaaab yyy', "a.*?y") 
#  [,1]  
# [1,] "aaaab y" 

Hier alle Saiten aaaab y, aaaab yy, aaaab yyy das Muster angepasst und begann in der gleichen Position, aber die erste war wegen des nicht-gierigen Musters zurückgegeben.


So was kann man die letzten ab zu fangen tun? Verwenden Sie dies:

str_match('xxx aaaab yyy', ".*(a.*b)") 
#  [,1]  [,2] 
# [1,] "xxx aaaab" "ab" 

Wie funktioniert es? Durch Hinzufügen eines gierigen Musters .* an der Vorderseite erzwingen Sie nun den Prozess, den letzten möglichen a in die erfasste Gruppe zu setzen.

+0

Danke @floder - Ich habe komplett vergessen, dass es immer von links zu beginnen beginnt. Die Leute diskutieren schon lange darüber: http://www.nntp.perl.org/group/perl.perl6.language.regex/2000/12/msg507.html –

3

Das Problem ist entspricht dem kürzesten Fenster zwischen zwei Strings. @ Flodel erwähnt korrekt, dass eine Regex-Engine die Zeichenfolge von links nach rechts analysiert, und daher sind alle Übereinstimmungen ganz links. Gierigkeit und Faulheit gelten nur für die rechten Grenzen: gierige Quantoren erhalten die Teilstrings bis zu den äußersten rechten Grenzen, und die faulen Quantoren werden bis zum ersten Auftreten der folgenden Teilstriche passen.

Siehe die Beispiele :

> library(stringr) 
> str_extract('xxx aaaab yyy', "a[^ab]*b") 
[1] "ab" 
> str_extract('xxx aaa xxx aaa zzz', "xxx.*?zzz") 
[1] "xxx aaa xxx aaa zzz" 
> str_extract('xxx aaa xxx aaa zzz', "xxx(?:(?!xxx|zzz).)*zzz") 
[1] "xxx aaa zzz" 

Die erste und die dritte Rück Szenarien der kürzeste Fenster, die zweite eine Darstellung des aktuellen Problem ist jedoch mit einem Multizeichen-Eingang.

Szenario 1. Grenzen einzelne Zeichen

Bei a und b sind einzelne Zeichen sind, ist der kürzeste Fenster unter Verwendung eines negierten Zeichenklasse gefunden. a[^ab]*b wird leicht den Teilstring von a bis zum nächsten b ohne a s und b s dazwischen greifen.

Szenario 2. Die Grenzen sind nicht einzelne Zeichen

Sie eine tempered greedy token in diesen Fällen verwenden können, die weiter abgerollt werden kann. Die xxx(?:(?!xxx|zzz).)*zzz Muster entspricht xxx, werden alle 0+ Zeichen anders als ein Zeilenumbruch char, der nicht der Ausgangs char eines xxx oder zzz char Sequenz (die (?!xxx|zzz) ist ein negativen Vorgriffs-, die das Spiel ausfällt, wenn die Teilzeichen unmittelbar rechts Einstimmungen das Lookahead-Muster) und dann eine zzz.

Diese Szenarien Anpassung kann leicht mit einer Base R regmatches (unter Verwendung eines PCRE regex Aroma, das Lookaheads unterstützt) verwendet werden:

> x <- 'xxx aaa xxx aaa zzz xxx bbb xxx ccc zzz' 
> unlist(regmatches(x, gregexpr("xxx(?:(?!xxx|zzz).)*zzz", x, perl = TRUE))) 
[1] "xxx aaa zzz" "xxx ccc zzz" 

Eine Anmerkung: Wenn ein PCRE regex in Basis R, oder die ICU Regex in str_extract/str_match, entspricht die . nicht Zeilenumbrüche Zeichen, um dieses Verhalten zu aktivieren, müssen Sie (?s) am Muster Start (ein Inline-DOTALL-Modifikator) hinzufügen.

Verwandte Themen