Suche Hack für Board
-
Ja, das hab ich mir auch gedacht... und da muss ich im NAchhinein sagen: Auch, wenn preg() und ereg() sehr mächtig sind, sollte man bei dieser Sache eher nicht damit arbeiten, weil da der Code x-mal durchgesehen wird. Ich weiß jetzt auch nicht, ob mein Code der optimalste ist, jedenfalls tauchen damit keine Fehler auf, so bleibe ich halt bei meinem Code, auch wenn sich einige deshalb ärgern werden.
-
-
Strogij schrieb:
@Dasd deine Methode ist zu kompliziert und auch recht langsam, man kommt ohne Regex aus, wenn man meinen Vorschlag in Betracht zieht.
Ja und nein. Zunächst sollte man sich ersteinmal Gedanken machen, ob es überhaupt sinnvoll ist, soetwas in PHP zu implementieren. Wozu sollte der Quelltext jedesmal neu geparst werden, wenn er sich nicht ändert? Da ist es sinnvoller, ihn einmal zu formatieren und dann abzuspeichern. Und in einem solchen Fall spielt die Zeit die das Skript benötigt keine Rolle.
Es gibt meines Erachtens nach keine Methode, die soetwas in einem angemessenen Zeitraum auch für größere Quelltexte (ab 100kB) durchführen kann. Da die PCRE in C implementiert ist und somit alle Zeigerfunktionen (vor allem char Zeiger) nutzen kann, ist sie _verdammt_ schnell. Weiterhin gibt es noch Optimierungsmöglichkeiten.
So kann man statt preg_replace zu verwenden die Offsets mittels preg_match_all capturen und dann einzeln ersetzen, was die Routine auf ungefähr die doppelte Geschwindigkiet bringen würde.
Dagegen gibt es bei deinem Ansatz auch Nachteile: mehrere Vorkommen ein- und desselben Strings werden immer wieder durchsucht und geparst. Außerdem: kompliziert ist meine Methode ganz gewiss nicht. Der Ansatz ist der einzige in meinen Augen funktionierende neben einem zeichenweisen Parser.
-
Jau, optimieren ist eine Sache, aber man sollte es nur einmal drüberlaufen lassen, da hast du schon Recht und in HTML-Version abspeichern, für die Änderungen zusätzlich noch die Original Version.
-
Dasd schrieb:
for ($index = count($highlight_data) - 1; $index >= 0; $index--) { if (!empty($highlight_data[$index]['matches'])) { foreach ($highlight_data[$index]['matches'] as $match) { $code = str_replace(md5($match), sprintf($highlight_data[$index]['tag'], $match), $code); } } }
Woher nimmst du das 'matches'?? - Bei mir steht jetzt, nachdem ich die Funktion verwendet habe... so komische md5-strings da... hier mal die Funktion, wie ich sie jetzt bei mir zu stehen habe:
function cpp($code) { $k=implode("",file("downloads/keywords/cpp.txt")); $k=str_replace("||","|",str_replace("\n","|",str_replace("\r\n","|",$k))); $k=explode("|",$k); $code=implode("",$code); $code=str_replace("\r\n","\n",$code); $code = htmlentities($code); $highlight_data = Array( Array('preg' => '~(/\*.*?\*/)~s', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(//.*)~', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(?:[\r\n]\s*)?(#.*?(?<!\\\\)(?:[\r\n]{1,2}))~s', 'tag' => '<span class="pre">%s</span>'), Array('preg' => '~(".*?(?<!\\\\)")~', 'tag' => '<span class="string">%s</span>'), Array('preg' => '~(?<![A-Za-z0-9_])(' . implode('|', $k) . ')(?![A-Za-z0-9_])~', 'tag' => '<span class="key">%s</span>'), Array('preg' => '~(?<![+\-0-9\.a-zA-Z])([+\-]?[0-9\.]+)(?![+\-0-9\.a-zA-Z])~', 'tag' => '<span class="int">%s</span>') ); for ($index = 0; $index < count($highlight_data); $index++) if (preg_match_all($highlight_data[$index]['preg'], $code, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $match) { if (!empty($highlight_data[$index]['matches']) && in_array($match[1], $highlight_data[$index]['matches'])) continue; $highlight_data[$index]['matches'][] = $match[1]; } $code = preg_replace($highlight_data[$index]['preg'] . 'e', 'md5("\\1")', $code); } for ($index = count($highlight_data) - 1; $index >= 0; $index--) if (!empty($highlight_data[$index]['matches'])) foreach ($highlight_data[$index]['matches'] as $match) $code = str_replace(md5($match), sprintf($highlight_data[$index]['tag'], $match), $code); return "<pre>$code</pre>"; }
Und raus kam bei einem Code das hier (bruchteil des codes):
ad9feadbb68dd8d9c826b13fad346f86#include <vcl.h> #pragma hdrstop #include "cppFinder.h" #include <dos.h> #include <dir.h> #include <string.h> #pragma package(smart_init) #pragma resource "*.dfm" TFinder *Finder; // Constructor of the form __fastcall TFinder::TFinder(TComponent* Owner) : TForm(Owner) { // String that user can see if no files found or if he aborts the search sNoFound=String("There are no files with this mask.") +String(" Try again in another directory."); } // Methode from the internet (delete a file into garbage pail) bool Delete(AnsiString FileName) { SHFILEOPSTRUCT FileOPStruct; 6366e23f3d7c714ec380870f15242d4f de1fae701180f569934eed927add2e9d d20356558672d84a76d3386adbb85d47
Finde ich etwas merkwürdig...
-
Achja, Anmerkung: An diesen Stellen, wo jetzt diese MD5-Strings stehen... standen mal Kommentare
- Windoof
-
OK, hab ein bissl dran herumgebastelt, das Problem war einfach, dass es ja auch Chars gibt, die mit einem Apostroph abngegeben werden. Außerdem habe ich noch ein Problem festgestellt und Beseitigt: Bei Präprozessordirektiven hast du das vorhergehende Zeilenumbruchzeichen ausgelassen... hier also die funktionierende Funktion:
function cpp($code) { $k=implode("",file("downloads/keywords/cpp.txt")); $k=str_replace("||","|",str_replace("\n","|",str_replace("\r\n","|",$k))); $k=explode("|",$k); $code=implode("",$code); $code=str_replace("'","'",htmlentities(str_replace("\r\n","\n",$code))); $highlight_data = Array( Array('preg' => '~(/\*.*?\*/)~s', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(//.*)~', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(#.*?(?<!\\\\)(?:[\r\n]{1,2}))~s', 'tag' => '<span class="pre">%s</span>'), Array('preg' => '~(".*?(?<!\\\\)")~', 'tag' => '<span class="string">%s</span>'), Array('preg' => '~('.*?(?<!\\\\)')~', 'tag' => '<span class="string">%s</span>'), Array('preg' => '~(?<![A-Za-z0-9_])(' . implode('|', $k) . ')(?![A-Za-z0-9_])~', 'tag' => '<span class="key">%s</span>'), Array('preg' => '~(?<![0-9\.a-zA-Z])([0-9\.]+)(?![0-9\.a-zA-Z])~', 'tag' => '<span class="int">%s</span>'), Array('preg' => '~(0x.?[0-9a-fA-F\.]+)(?![0-9a-fA-F\.])~', 'tag' => '<span class="int">%s</span>') ); for ($index = 0; $index < count($highlight_data); $index++) if (preg_match_all($highlight_data[$index]['preg'], $code, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $match) { if (!empty($highlight_data[$index]['matches']) && in_array($match[1], $highlight_data[$index]['matches'])) continue; $highlight_data[$index]['matches'][] = $match[1]; } $code = preg_replace($highlight_data[$index]['preg'] . 'e', 'md5("\\1")', $code); } for ($index = count($highlight_data) - 1; $index >= 0; $index--) if (!empty($highlight_data[$index]['matches'])) foreach ($highlight_data[$index]['matches'] as $match) $code = str_replace(md5($match), sprintf($highlight_data[$index]['tag'], $match), $code); return "<pre>$code</pre>"; }
EDIT: Hexadezimale Zahlen wurden bei dir auch nicht gecaptured... hab da nochwas eingefügt.
-
So, noch ein Problem: So werden innerhalb von Strings auch Kommentare gecastet..., bsp. das hier: "Dies ist ein String... //Test", da wird //Test" als Kommentar gemacht. Ich habe an der Reihenfolge herumgespielt und dabei ist das hier herausgekommen:
$highlight_data = Array( Array('preg' => '~(#.*?(?<!\\\\)(?:[\r\n]{1,2}))~s', 'tag' => '<span class="pre">%s</span>'), Array('preg' => '~(".*?(?<!\\\\)")~', 'tag' => '<span class="string">%s</span>'), Array('preg' => '~('.*?(?<!\\\\)')~', 'tag' => '<span class="string">%s</span>'), Array('preg' => '~(/\*.*?\*/)~s', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(//.*)~', 'tag' => '<span class="comment">%s</span>'), Array('preg' => '~(?<![A-Za-z0-9_])(' . implode('|', $k) . ')(?![A-Za-z0-9_])~', 'tag' => '<span class="key">%s</span>'), Array('preg' => '~(?<![0-9\.a-zA-Z])([0-9\.]+)(?![0-9\.a-zA-Z])~', 'tag' => '<span class="int">%s</span>'), Array('preg' => '~(0x.?[0-9a-fA-F\.]+)(?![0-9a-fA-F\.])~', 'tag' => '<span class="int">%s</span>') );
So werden zwar noch Strings in Kommentaren eingefärbt, aber das ist akzeptabel. Frage dennoch: Wie kann man dieses Problem beseitigen? Ich sehe da keinen Weg... Einziger Vorteil gegenüber meiner Funktion: Ist etwa 4-mal so schnell...
reicht als Argument.
-
Upps... habe wohl in der Zwischenzeit übersehen, dass es hier noch weiterging...
Falls Antworten noch interessant sein sollten:
Das Problem ist, dass Pregs im Allgemeinen kontextfrei sind. Das bedeutet, ein Ausdruck ist nicht in der Lage zu erkennen, in welcher Umgebung er sich befindet. Ein Kommentar kann also i.A. nicht wissen, ob er in einem String steht und ein String nicht, ob er in einem Kommentar steht usw. Mit Pregs kann man das nur umgehen, indem man die komplette (mögliche) Syntax - also C als Programmiersprache - als einen Ausdruck zusammenstellt. Ein Ding der Unmöglichkeit. Bei begerenzten "Sprachen" (wie z.B. den Tags von Smarty) lässt sich soetwas noch bewerkstelligen.
Der einzige andere Ausweg ist, wie du dir wahrscheinlich schon denken kannst, ein zeichenweiser Interpreter.
Um noch ein wenig Fachgeplänkel dazuzupacken: Mit Pregs lassen sich nur reguläre Sprachen (sagt ja schon der Name) erkennen. Für eine komplette Sprache benötigt man dann schon eher eine Turingmaschine. Und die entspricht in ungefähr einem zeichenweisen Interpreter.
Das Infostudium ist also doch für etwas gut...
-
Das reicht so schon, ich hab das so gemacht, dass Strings in Kommentaren möglich sind, aber umgekehrt nichtmehr, das ist soweit akzeptabel. Hab die Funktion inzwischen auch für andere Sprachen verwendet, wie etwa PHP, Delphi, SQL...