• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

preg_match_all: Genauere Suche und Array in String zerlegen

aJunkie

Mitglied
Hallo,

ich komme gerade nicht weiter, wenn ich den Script sinnvoll kurz halten will.

Und zwar lade ich eine Seite ein:
PHP:
        $url     = file_get_contents("http://example.org") or die("Seite konnte nicht geladen werden."); # Seite öffnen bzw. laden
        preg_match_all("!<a href=\"datei.php(.*)\" title=\"([a-zA-Z\d])\"!",$url,$ergebnis,PREG_PATTERN_ORDER,40000); # Suchen und Ergebnisse in $ergebnis speichern


  foreach ($ergebnis as $link){ # Suchergebnisse in Array ausgeben
    print_r($link)."\n";
    }
Das erste: Wie kann ich den "title" auslesen. Die Seite enthält viele Links mit 'title'. Ich brauche aber nur die, die auf datei.php verlinken.
Das Muster ist immer das selbe.
Es ist ein <a href="datei?verschiedeneVariablen&mitUnterstrichETC" title="will ich auslesen">Hier steht das selbe wie in 'title'</a>

Ich habe (.*) hinter 'datei.php' geschrieben, da ich nicht weiß, wie die URL gebaut ist. Es enthält Variablen, die ich nicht brauche. Aber verlinkt wird immer auf datei.php.

Dann sollen die Ergebnisse ("title") untereinander ausgegeben werden. Keine Array, etc, weil ich die Ergebnisse dann später komfortabler weiterverarbeiten kann.

Mit dem Beispiel oben wird nur
Code:
Array ( ) Array ( ) Array ( )
ausgegeben.
Wenn ich aber die Suche locker, funktionierts, was nicht der Sinn und Zweck ist, wenn ich nach
Code:
<div id="information">(.*)</div>
suche, denn die Hälfte der Ergebnisse kann ich nicht gebrauchen.

Hoffe, jemand kann mir helfen. Mit reg. Ausdrücken hatte ich bisher nichts am Hut.
 
Ich habe (.*) hinter 'datei.php' geschrieben, da ich nicht weiß, wie die URL gebaut ist. Es enthält Variablen, die ich nicht brauche. Aber verlinkt wird immer auf datei.php.

Sowas lässt sich üblicherweise als '!<a href="datei\.php[^"]*" title="([^"]*)"!' schreiben.

[^"]* steht für "beliebig viele Zeichen, die nicht das Anführungszeichen sind".

So ziemlich das Wichtigste, was über reguläre Ausdrücke zu wissen ist: Sie sind standardmäßig greedy.

- Regex Tutorial - Repetition with Star and Plus

Das Zweitwichtigste sind Pattern modifiers:

- PHP: Possible modifiers in regex patterns - Manual

Nehmen wir mal diese Beispieleingabe:

Code:
<div id="information">
    <p>ein test</p>
</div>
<p>hier kommt mehr inhalt</p>
<div class="example">Hallo Welt!</div>

Was matcht !<div id="information">(.*)</div>! ?

Gar nichts, denn der s-Modifier (PCRE_DOTALL) ist standardmäßig nicht gesetzt, wodurch der Punkt (.) keine Zeilenumbrüche einschließt.​

Was matcht !<div id="information">(.*)</div>!s ?

Code:
<div id="information">[COLOR="Red"]
    <p>ein test</p>
</div>
<p>hier kommt mehr inhalt</p>
<div class="example">Hallo Welt![/COLOR]</div>

Ausdrücke sind standardmäßig greedy. (.*)</div> matcht nicht bis zum ersten Vorkommen von </div>, sondern bis zum letzten. Ein Fragezeichen hinter dem Quantifikator (dem Punkt) kehrt dieses Verhalten um.​

Was matcht !<div id="information">(.*?)</div>!s ?

Code:
<div id="information">[COLOR="Red"]
    <p>ein test</p>
[/COLOR]</div>
<p>hier kommt mehr inhalt</p>
<div class="example">Hallo Welt!</div>

Wunderbar. Das ist vermutlich das, was wir wollten.

Hinweis: Es gibt einen Pattern modifier (U, PCRE_UNGREEDY), der "greediness" standardmäßig in "lazyness" umwandelt. Der könnte hier anstelle des Fragezeichens eingesetzt werden. (Das Fragezeichen würde dann aus "lazyness" wiederum "greediness" machen, wenn U gesetzt ist.) Ich rate jedoch von der Verwendung von U ab, da es meiner Ansicht nach einfacher zu merken und zu lesen ist, "Quantifikator = greedy" und "Quantifikator mit Fragezeichen = ungreedy/lazy" anzunehmen.​
 
Danke. =)

So habe ich es jetzt hinbekommen.

PHP:
        $url     = file_get_contents("http://example.org") or die("Seite konnte nicht geladen werden.");
        preg_match_all('!"datei\.php[^"]*" title="([^"]*[^Standardtext])">!',$url,$ergebnis,PREG_SET_ORDER,40000);

  foreach ($ergebnis as $link){
    echo($link[1])."\n";
    }
 
[^Standardtext] bedeutet: "Ein Zeichen, das nicht a, d, e, n, t, r, x, S ist."

Das heißt, wenn der Inhalt des title-Attributs mit einem dieser Zeichen endet, gibt es kein Match. Eine Charakterklasse "[...]" ist kein Capturing Pattern "(...)". Capturing Patterns lassen sich nicht so ohne weiteres negieren. Reguläre Ausdrücke sind generell besser darin, zu prüfen, ob Zeichen vorhanden sind, statt zu prüfen, ob Zeichen nicht vorhanden sind.
 
Regex ist für diese Aufgabe ohnehin nicht geeignet. Lieber DOMDocument oder gleich FluentDOM für so etwas benutzen.
 
@mermshaus: Aber es funktioniert. :D Alle diese Buchstaben werden trotzdem gematcht.

Ich filtere damit den 'Standardtext' aus. Das Wort an sich und nicht die Buchstaben.
Ich weiß auch nicht, wie ich es endlich hinbekam, aber es klappt.

Mit DOMDoc kenn ich mich noch nicht aus, aber da hätte ich auch geregext. Hm.
Edit: Achso, getelementsby...?
 
Zuletzt bearbeitet:
Nein, es gibt deshalb kein Match, weil "Standardtext" mit einem dieser Buchstaben endet. Das gilt für jedes andere Wort, für das diese Bedingung erfüllt ist. Beispiel:

PHP:
<?php

$url = <<<EOT
<a href="datei.php&amp;abc" title="Test">
<a href="datei.php&amp;abc" title="hallo">
<a href="datei.php&amp;abc" title="xyz123">
<a href="datei.php&amp;abc" title="Standardtext">
<a href="datei.php&amp;abc" title="needs a fix">
EOT;

preg_match_all('!"datei\.php[^"]*" title="([^"]*[^Standardtext])">!',
        $url,$ergebnis,PREG_SET_ORDER);

foreach ($ergebnis as $link){
    echo($link[1])."\n";
}

Die Ausgabe davon ist:

Code:
hallo
xyz123

"Test" und "needs a fix" enden auch mit einem der Buchstaben aus [^Standardtext].

Wie gesagt, das ist als

Code:
not in array('S', 'a', 'd', 'e', 'n', 'r', 't', 'x')

zu interpretieren.

Was du willst, ließe sich wahrscheinlich so schreiben:

PHP:
preg_match_all('#"datei\.php[^"]*" title="(?!Standardtext)([^"]*)">#',
        $url,$ergebnis,PREG_SET_ORDER);

Ausgabe:

Code:
Test
hallo
xyz123
needs a fix

(?! ... ) ist eine negative Assertion.

- PHP: Assertions - Manual

Mit DOMDoc kenn ich mich noch nicht aus, aber da hätte ich auch geregext. Hm.
Edit: Achso, getelementsby...?

DOMDocument ist ein sehr mächtiges Werkzeug, vor allem im Zusammenspiel mit XPath-Queries.

- PHP: DOMDocument - Manual
- PHP: DOMXPath - Manual
- XPath

Es lohnt sich, den Umgang damit zu lernen.
 
Zuletzt bearbeitet:
Zurück
Oben