Archiv verlassen und diese Seite im Standarddesign anzeigen : Mal wieder: RegExp überall, außer im Link
xmedia2000 05-03-2007, 11:41 Also. Hab die Suche bemüht, jedoch ohne wirklichen Erfolg.
Zum Problem:
Ich habe eine Suche, die im Ergebnis das gesuchte Wort im gesamten Text farblich markiert.
$pattern = "/(([<?>]*)|$suchwort)/ie";
echo preg_replace($pattern,'"\2"=="\1"? "\1":"<span style=\"background-color:$highlightcolor;font-weight:bold;\">\1</span>"', $suchwort);
Funktioniert wunderbar. Das Problem ist, das auch in HTML Tags gesucht wird. So z.B. in einem Link mit mehreren Varibalen z.B: index.php?var1=value1&var2=value2 etc.
Dann hab ich im Link auch die Ersetzung mit <span> stehen. Passt also nicht. Gibts da eine Regel um, nicht in <a Tags zu suchen??
Danke schonmal vorab für die Hilfe.
ghostgambler 05-03-2007, 14:14 Würd ich mit negativen Assertions machen, irgendwas wie davor kein < und dahinter kein > mit ungreedy und sonst kein <> in den Zeichen zwischen Suchstring und >/<
xmedia2000 05-03-2007, 14:37 Denken kann ich mir das auch, nur leider hab ich keinen Ansatzpunkt für die passende Expression dazu...
Meine derzeitigen Pattern:
$pattern = "/((<[^>]*)|$suchwort)/ieU";
geht auch, nur wie mach ich das mit davor kein "<" kommen darf und dahinter kein ">" kommen darf...
xmedia2000 07-03-2007, 09:15 Hab das ganze nun folgendermaßen gelöst.
$searchterm = trim($searchterm);
$pattern = "/((<[^>]*)|".$searchterm.")/is";
$replacestart = "<i>";
$replaceend = "</i>";
$doc = new DOMDocument("1.0", "UTF-8");
$doc->preserveWhiteSpace = false;
$doc->loadHTML($searchtext);
if($doc) {
$cells = $doc->getElementsByTagName("td"); // Lade TD Nodes
foreach($cells as $cell) {
$cell->nodeValue = preg_replace($pattern, $replacestart.'\\1'.$replaceend, $cell->nodeValue);
}
echo $doc->saveHTML();
} else {
echo "Fehler beim Laden des Dokuments per PHP DOM.";
}
Meine HTML Datei ($searchtext) wird per DOM eingelesen und ich lasse dann einfach nur in allen TD Zellen ersetzen.
Meinen Link hab ich einfach per TD onclick gemacht.
Funktioniert soweit auch. Ein Problem hab ich aber immernoch.
Jetzt schreibt er mir & lt i & gt TEST & lt /i & gt, statt <i>TEST</i>...
Hab schon mit html_entities_decode gespielt. Macht er aber nicht...
Hat jemand evtl. noch eine Idee?
Original geschrieben von xmedia2000
Jetzt schreibt er mir & lt i & gt TEST & lt /i & gt, statt <i>TEST</i>...
Na was ein Wunder ...
Was ist das für ein Knoten, dessen Inhalt du da bearbeitest? Richtig, (höchstvermutlich) ein Textknoten.
Du nimmst doch nicht ernsthaft an, der würde aufgeplittet und ein Elementknoten eingefügt, nur weil du im Textknoteninhalt < und > einfügst ...?
Wenn du ein neues Element willst, musst du das schon mit DOM-Methoden erzeugen und einhängen.
xmedia2000 07-03-2007, 09:49 Mmh.
Stimmt. Da könntest du recht haben... ;)
Ok. Darauf bin ich jetzt irgendwie nicht gekommen...
tontechniker 07-03-2007, 10:29 ich würde das dom system nicht benutzen da es für ein produktives system imho viel zu langsam ist (regex ist nicht viel besser aber in diesem fall einfacher)
du kannst einfach mit einem lookaround arbeiten
$pattern = "/(?<!\<.*?)((\<[^\>]*)|$suchwort)(?!.*?\>)/ieU"; sollte soweit gehen ist aber ungetestet
xmedia2000 07-03-2007, 10:44 @tontechniker:
preg_replace wäre mir auch lieber...
Aber die pattern passen nicht. hab noch ein wenig probiert, ohne erfolg...
Er findet zwar alles und ersetzt nicht im link, aber auch nicht das ergebnis mit <span></span>
xmedia2000 07-03-2007, 10:50 also mit DOM klappts nun:
hier der funktionierende code: (mit Sicherheit nicht die eleganteste Lösung)
$searchterm = trim($searchterm);
$doc = new DOMDocument("1.0", "UTF-8");
$doc->preserveWhiteSpace = false;
$doc->loadHTML($searchtext);
if($doc) {
$cells = $doc->getElementsByTagName("td"); // Lade TD Nodes
foreach($cells as $cell) {
if(preg_match("/".$searchterm."/is", $cell->nodeValue))
{
$zellen_inhalt = $cell->nodeValue; // Erst den Inhalt speichern
$cell->nodeValue = ""; // Zelleninhalt leeren
$bold = $cell->appendChild(new DOMElement("span")); // Span style hinzufügen
$bold->setAttribute("style", "background-color:".$highlightcolor.";font-weight:bold");
$bold->nodeValue = $zellen_inhalt; // Inhalt in span setzen
}
}
echo $doc->saveHTML();
} else {
echo "Fehler beim Laden des Dokuments per PHP DOM.";
}
tontechniker 07-03-2007, 10:52 ich hab dir doch ein stichwort gepostet wie es mit preg_replace gehen sollte - kommst du damit nicht weiter?
xmedia2000 07-03-2007, 10:59 doch. aber die gehen auch nicht...
hab die RegExp noch nie kapiert...
tontechniker 07-03-2007, 11:15 $lastfound = 0;
$searchtext = 'Die ist ein <acronym title="HTML">HTML</acronym> Dokument.';
$searchterm = 'html';
$text = $searchtext;
while ( $startpos = strpos ( $searchtext, '<', $lastfound ) {
$text = str_ireplace ( $searchterm, '<span style="...">' . $searchterm . '</span>', substr ( $text, $lastfound, $startpos - $lastfound );
$lastfound = strpos ( $searchtext, '>', $starpos );
} das sollte wesentlich schneller sein (sollte das so nicht ganz funktionieren lass die kurz die strings ausgeben evtl. stimmen die zeichenpositionen nicht ganz) - das ganze läuft auch noch in einer schleife oder?
jahlives 07-03-2007, 12:26 Habe ich anno dazumal für meine Suchfkt auf der Seite verwendet
$str = preg_replace("/((<[^>]*)|b".$suche."b/ie",'"\\\2"=="\\\1" : "<span style=\"background-color:yellow\">\\\00</span>"',$deinString);
Gruss
tobi
xmedia2000 07-03-2007, 13:25 @ jahlives.
Danke, aber den Pattern hatte ich schon.
Geht zwar, aber eben auch in Links.
Da Problem ist, das ich eine ganze HTML einlese. Ich denke aber, das meine DOM Methode dort schneller ist, da ja nur TD Zellinhalte geparst werden und preg_replace würde auf alle Elemente angewendet.
Man muss dazu sagen, das ich eine Seite habe, die eine riesige Tabelle enthält... Ohne divs o.ä.
jahlives 07-03-2007, 13:29 Geht zwar, aber eben auch in Links.
Heisst das, dass dir auch Teile ersetzt werden, die zwischen <a und > stehen ? Kann eigentlich nicht sein...
Oder meinst du den Linktext ?
Gruss
tobi
xmedia2000 07-03-2007, 13:42 Ich weiß.
Klingt komisch, ist aber so...
Mal zur Veranschaulichung:
<td onlick="index.php?var1=schlumpf">Schlumpf</td>
Es wird ersetzt zu:
<td onlick="index.php?var1=<span>schlumpf</span>"><span>Schlumpf</span></td>
Original geschrieben von xmedia2000
Ich denke aber, das meine DOM Methode dort schneller ist, da ja nur TD Zellinhalte geparst werden und preg_replace würde auf alle Elemente angewendet.
Und XML parsen kostest gar nichts, meinst du ...?
<td onlick="index.php?var1=schlumpf">
Warum redest du von Links, wenn es sich gar nicht um Links handelt?
jahlives 07-03-2007, 13:57 Also bei meiner Suchfkt mit diesem RegExp passiert definitiv ned :dontknow:
Bitte mal den ensprechenden Code posten
Gruss
tobi
xmedia2000 07-03-2007, 14:04 Und XML parsen kostest gar nichts, meinst du ...?
Hier mit microtime() errechnete Zeit für DOM: 0.003043
Hier mit microtime() errechnete Zeit für preg_replace: 0.093879
Warum redest du von Links, wenn es sich gar nicht um Links handelt?
Weil es völlig wurscht ist, ob es onclick oder <a href> ist. Habe beide Varianten schon probiert.
xmedia2000 07-03-2007, 14:11 @jahlives:
Kuckst du hier:
Funktion in ausgelagerter Datei:
function highlightSearchtext ($searchtext, $searchterm, $highlightcolor) {
$searchterm = trim($searchterm);
$pattern = "#((<[^>]*)|$searchterm)#ieU";
echo preg_replace($pattern, '"\2"=="\1"? "\1":"<span style=\"background-color:'.$highlightcolor.';\"><b>\1</b></span>"', $searchtext);
}
ausführende Datei, wobei $output reiner HTML Quelltext (unterhalb <body>) ist.
highlightSearchtext($output, $_REQUEST['suchausdruck'], '#FFFF99');
:dontknow: :dontknow: :dontknow:
jahlives 07-03-2007, 14:25 Mein RegExp verwendet aber die Referenz \0 und nicht die Ref \1 !
Habe gerade eben noch bei mir auf dem Server geschaut wie der RegExp dort ausschaut (der Code funzt kannste hier (http://911-research.info/911/suche.php) testen)
$test = preg_replace("/((<[^>]*)|\b$text\B)/ei",'"\\2"=="\\1"? "\\1" : "<span style=\"background-color:yellow;\">\\0</span>"',$temp);
Code Tags musste ich nehmen damit mir die Backslashes nicht gefressen werden.
Mit dem Modifikator \b und \B kannst du festlegen ob der Treffer am Anfang eines Wortes, als ganzes Wort oder irgendwo im Text vorkommen soll
Gruss
tobi
xmedia2000 07-03-2007, 15:32 Ok.
Funktioniert, habe jetzt aber ein anderes Problem.
jetzt maskiert er alle einfachen Anführungszeichen ' zu \\'...
<td onclick="location.href=\\'index.php?var1=schlumpf\\'><span>Schlumpf</span></td>
Ergo hab ich jetzt JavaScript Fehler und mein Link geht nicht.
jahlives 07-03-2007, 16:03 Und was hindert dich daran vor der Rückgabe des Strings ein stripslashes() über den String zu lassen ?
Gruss
tobi
xmedia2000 07-03-2007, 16:31 Nix. :D
Bin nur anfänglich nicht darauf gekommen.
Hab ich schon gemacht und funzt jetzt alles von die feinst....
Vielen Dank für Eure Mühen. :jo:
tontechniker 07-03-2007, 16:47 <?php
$lastfound = 0;
$text = 'Dies ist ein <acronym title="HTML">HTML</acronym> Dokument.';
$searchterm = 'html';
while ( $startpos = strpos ( $text, '<', $lastfound ) ) {
$subtext = substr ( $text, $lastfound, $startpos - $lastfound );
$text = str_ireplace ( $subtext, str_ireplace ( $searchterm, '<b>' . $searchterm . '</b>', $subtext ), $text );
$lastfound = strpos ( $text, '>', $startpos );
}
echo $text;
?>... hab mal meinen vorschlag korigiert - ich wette das ist schneller und verursacht nebenbei auch keine slashes $lastfound korigiert
Original geschrieben von tontechniker
ich wette das ist schneller
Und was macht es aus
$text = 'Dies ist ein <a href="xyz.HTML">Link</a> <acronym title="HTML">HTML</acronym> Dokument.';
...?
Und bei
$text = 'Dies ist ein <a href="xyz.HTML">Link</a>, gefolgt von einem <acronym title="HTML">HTML</acronym> Element.';
schlägt mir reproduzierbar sogar die max_execution_time (von 10 Sekunden auf dem Testsystem) zu.
jahlives 07-03-2007, 16:58 @tontechniker
Glaube auch nicht dass dies schneller ist. Mittels des RegExp lasse ich eine Suche über 65 Dateien unter 1 Sekunde durchlaufen. Mit deinem werde ich das gar nicht erst probieren :D
Ausserdem ist die Flexibilität für eine Suche mittels RegExp grösser --> Modifikatoren ändern und die Suche funzt schon ganz anders (z.B. nur Wortbeginn, ganzes Wort, oder nur im Wort enthalten)
Gruss
tobi
tontechniker 07-03-2007, 17:06 Und was macht es aus...?
Und bei
...
schlägt mir reproduzierbar sogar die max_execution_time (von 10 Sekunden auf dem Testsystem) zu. funktioniert beides ohne probleme?
zur zeit: bei diesem einfachen String braucht die Schleife 0.000184 und der Regex 0.000292 ... glaub ja nicht das es schneller wird
jahlives 09-03-2007, 09:42 zur zeit: bei diesem einfachen String braucht die Schleife 0.000184 und der Regex 0.000292 ... glaub ja nicht das es schneller wird
Kann bei diesem einfachen String ja sein, dass deine Version schneller ist. Was aber wenn du 16000 Treffer markieren mussst ? Dauert bei mir Pi mal Auge 1-2 Sekunden (je nachdem wie ausgelastet der Server ist).
Und ausserdem ist deine Version wie bereits angetönt, alles andere als flexibel.
Ich werde deine Code mal auf die 16000 Treffer loslassen zum Benchmarken und da Ergebnis hier posten.
Gruss
tobi
jahlives 10-03-2007, 19:59 @tontechniker
Habe deinen Code und meinen jetzt im Benchmark mal gegeneinander laufen lassen. Zuerst wollte ich in einer Schleife die Suche in einer 89 kb Datei 100x durchlaufen lassen und die Zeiten messen. Mit dem RegExp geht das ohne Probleme und dauert ca 50 Sekunden (Gesamtlaufzeit). Einzelne Zeiten liegen zwischen 0,4 und 0,8 Sekunden pro Durchlauf.
Dein Code kann die Suche nicht einmal bei einem Durchlauf innerhalb der Max Execution Time (360 Sekunden) durchlaufen !
Es ist klar, dass dein Code bei einem sehr kurzen zu durchsuchenden Text schneller ist, weil du die RegExp Engine ja nicht anwerfen musst. Die oben genannten 0.8 Sekunden gelten nur für den ersten Durchlauf, danach liegen die Zeiten eher bei 0.4 s.
Soviel zum Benchmark ;)
Gruss
tobi
tontechniker 11-03-2007, 13:30 ok du hast recht, hab das ganze gerade selber mal getestet - der regex läuft durch, die string ersetzung nicht
allerdings finde ich immernoch das es bei einem template system z.b. sinnvoller ist auf regex zu verzichtet :rolleyes:
|
-
- |