2011-01-03 5 views
4

Dies ist ein komisches Problem, das ich angetroffen habe (und wahrscheinlich schon gesehen habe, aber nie beachtet habe).Wie bekomme ich eine Regex, um am Anfang einer Zeichenkette zu beginnen?

Hier ist der Kern des Codes:

my $url = 'http://twitter.com/' . $handle; 
my $page = get($url); 

if($page =~ m/Web<\/span>\s*<a href=\"(.+?)\"/gi) { 
    $website = $1; 
} 

if($page =~ m/follower_count\" class=\"stats_count numeric\">(.+?)\s*</g) { 
    $num_followers = $1; 
} 

Es wird eine twitter url und tut ein bisschen regex die Anzahl der Anhänger und die Website des Benutzers zu erfassen. Dieser Code funktioniert tatsächlich gut. Wenn Sie jedoch die Bestellung wechseln und nach der Website suchen, NACHDEM Sie nach einem Follower suchen, wird die Website leer angezeigt. Wie es sich herausstellt, wenn Sie eine Zeichenfolge regexen, scheint es, den Speicherort der letzten Übereinstimmung zu speichern. Im HTML-Format wird die Anzahl der Follower nach der Anzeige der Website angezeigt. Wenn Sie den Follower-Count-Regex zuerst tun, ist es so, als ob er den Regex der Website startet, wo der Follower-Count endet (wie ein Index-Verweis auf den String).

Was mich verblüfft ist, dass ich den "g" -Operator am Ende habe, was "global" bedeutet, wie in "Suche die Zeichenfolge global ... von Anfang an".

Fehle ich hier etwas? Ich kann nicht herausfinden, warum es die letzte Regex-Position auf der Saite wieder aufnimmt (wenn das Sinn macht).

+1

könnten Sie die 2 Beispiele von Textzeilen einschließen, die Sie die Regex bitte anwenden – DaveC

+0

Dies wurde beantwortet, aber 2 kleinere Klarstellungen: 1- mit "g" in einem s/etwas/somethingselse/g; ist notwendig, um alle Vorkommen zu ersetzen, ja? 2- Der "m" Operator, den ich in meinem obigen Beispielcode habe, ist nicht notwendig. – Jeff

+0

1. ja, 's /// g' ersetzt global, während' s /// 'einen einzelnen ersetzt. 2. ja. du brauchst * nur * 'm', wenn du verschiedene Klammern verwendest:' m (Muster) 'oder' m [Muster] 'oder so ähnlich. –

Antwort

12

Der Modifikator /g, im skalaren Kontext, tut nicht, was Sie denken, dass es tut. Werde es los.

Wie perlretut erklärt, /g in skalaren Kontext Zyklen über jedes Spiel der Reihe nach. Es ist für den Einsatz in einer Schleife ausgelegt, etwa so:

while ($str =~ /pattern/g) { 
    # match on each occurence of 'pattern' in $str in turn 
} 

Der andere Weg /g zu verwenden, in Listenkontext ist:

my @results = $str =~ /pattern/g; # collect each occurence of 'pattern' within $str into @results 

Wenn Sie /g in Skalarkontext verwenden und du bist nicht wenn man darüber hinweggeht, benutzt man es mit ziemlicher Sicherheit nicht richtig.

+2

AH! Ich wusste, dass ich das schon so oft benutzt habe (in While Loops, genau wie du sie beschreibst) Ich habe vergessen, wofür es gedacht war! Jetzt macht das Sinn. Vielen Dank! – Jeff

0

m // g setzt die Position nicht zurück. Sie müssen das manuell tun. Sehen Sie dieses als Referenz: http://perldoc.perl.org/functions/pos.html

Ich glaube, dass Sie pos auf 0 oder undef setzen und es wird funktionieren.

+1

Es ist nicht notwendig, 'pos' hier zu verwenden. Das Flag "/ g" muss überhaupt nicht verwendet werden. – friedo

5

perlop on Regexp Quote Like Operators zu zitieren:

Im skalaren Kontext wird jede Ausführung von m//g die nächste Übereinstimmung findet, gibt true zurück, wenn es passt, und falsch, wenn es keine weitere Übereinstimmung vorhanden ist. Die Position nach der letzten Übereinstimmung kann mit der Funktion pos() gelesen oder eingestellt werden; siehe pos. Eine fehlgeschlagene Übereinstimmung setzt normalerweise die Suchposition auf den Anfang der Zeichenfolge zurück, aber Sie können das vermeiden, indem Sie den /c-Modifizierer hinzufügen (z. B. m//gc). Durch Ändern der Zielzeichenfolge wird auch die Suchposition zurückgesetzt.

So in Skalarkontext (die Sie verwenden), /g nicht „von Anfang an suchen“ bedeutet, es bedeutet „aus der Zeichenfolge des Suchstart pos“. "Von Anfang an suchen" ist die Standardeinstellung (ohne /g).

/g wird normalerweise verwendet, wenn Sie alle Matches für einen regulären Ausdruck in einem String finden wollen, anstatt nur das erste Spiel.Im Listenkontext wird eine Liste aller Übereinstimmungen zurückgegeben. Im skalaren Kontext startet man die Suche dort, wo die vorherige Suche aufgehört hat (normalerweise in einer Schleife).

2

Der Kern davon ist, dass mit/g getan Streichhölzern, die Position des letzten Spiels zu speichern, so dass das nächste Mal, dass Zeichenfolge übereinstimmt, wird die Regex von dort aus starten. Im skalaren Kontext wird dies im Allgemeinen durchgeführt, um mehrere aufeinander folgende Übereinstimmungen in einer while-Schleife zu erhalten. Im Listenkontext gibt/g alle übereinstimmenden (aber nicht überlappenden) Ergebnisse zurück. Sie können mehr darüber unter perlretut unter Global Matching und unter perlop unter Regexp-Quote-Like-Operators lesen.

Sie können die aktuelle Position mit der pos Funktion sehen. Sie können die Position auch festlegen, indem Sie pos als Lvalue verwenden: pos($string) = 0; setzt die Position auf den Anfang der Zeichenfolge zurück.

Es gibt nicht viel Grund/verwenden g in Skalarkontext außerhalb einer Schleife, wie Sie genau die gleiche Funktionalität mit der \ G Behauptung zu bekommen.

..natürlich, dann erinnert sich niemand, wie \ G arbeitet und Sie sind wieder auf Platz eins, aber das ist ein anderes Thema.

Verwandte Themen