Suche Hack für Board
-
Hi,
ich suche einen Hack für ein Board (phpBB oder Invisionboard (vorzugsweise!)).
Der Hack ist ein einfaches SyntaxHighlight für C++ Tags und/oder PHP Tags.
Hat da jemand nen guten Link? Bei Google finde ich absolut nichts.
-
Warum schreibst du dir sowas nicht einfach selber ? oder schaust mal die standard funktionen an bei php.net
-
gib mir ein beispiel und ich machs. Am liebsten wäre mir ein beispiel von PHP Syntaxhighlight.
-
Nicht ganz ernst gemeint: highlight_string()
-
Ich hab letztens was für C++ gemacht wegen Highlighting... ist ebenfalls ein PHP-Script. Interesse?
-
Ja!!!
-
Windoof schrieb:
Ich hab letztens was für C++ gemacht wegen Highlighting... ist ebenfalls ein PHP-Script. Interesse?
JAAA BITTE POSTEN!!!
-
<?php function code($sl) { $k=array( "AnsiString", "bool", "break", "byte", "case", "catch", "char", "class", "const", "continue", "delete", "do", "double", "dynamic_cast", "else", "extern", "false", "__fastcall", "__finally", "float", "for", "if", "int", "__int64", "long", "new", "operator", "private", "__property", "protected", "public", "__published", "return", "signed", "static_cast", "string", "String", "switch", "true", "try", "unsigned", "void", "while"); $comment=false; for ($i=0;$i<count($sl);++$i) { $sl[$i]=htmlentities($sl[$i]); $e=true; $s=false; $c=false; $integer=false; for ($j=0;$j<strlen($sl[$i]);++$j) { for ($x=0;$x<count($k);++$x) if ( substr($sl[$i],$j,strlen($k[$x]))==$k[$x] && !$s && !$c && !$comment && ($sl[$i][$j-1]<'a' || $sl[$i][$j-1]>'z') && ($sl[$i][$j-1]<'A' || $sl[$i][$j-1]>'Z') && ($sl[$i][$j-1]<'0' || $sl[$i][$j-1]>'9') && $sl[$i][$j-1]!='_' && ($sl[$i][$j+strlen($k[$x])]<'a' || $sl[$i][$j+strlen($k[$x])]>'z') && ($sl[$i][$j+strlen($k[$x])]<'A' || $sl[$i][$j+strlen($k[$x])]>'Z') && ($sl[$i][$j+strlen($k[$x])]<'0' || $sl[$i][$j+strlen($k[$x])]>'9') && $sl[$i][$j+strlen($k[$x])]!='_') { $sl[$i]=substr($sl[$i],0,$j)."<span class=\"key\">".$k[$x]."</span>".substr($sl[$i],$j+strlen($k[$x]),strlen($sl[$i])); $j+=strlen($k[$x])+25; break; } if ($sl[$i][$j]>='0' && $sl[$i][$j]<='9' && !$s && !$c && !$comment && !$integer && ($sl[$i][$j-1]<'a' || $sl[$i][$j-1]>'z' || $sl[$i][$j-1]=='x') && ($sl[$i][$j-1]<'A' || $sl[$i][$j-1]>'Z' || $sl[$i][$j-1]=='X') && ($sl[$i][$j-1]<'0' || $sl[$i][$j-1]>'9') && $sl[$i][$j-1]!='.') { $integer=true; $sl[$i]=substr($sl[$i],0,$j)."<span class=\"int\">".substr($sl[$i],$j,strlen($sl[$i])); $j+=17; continue; } else if ($integer && ($sl[$i][$j]<'0' || $sl[$i][$j]>'9') && $sl[$i][$j]!='.' && strtolower($sl[$i][$j])!='x' && (strtolower($sl[$i][$j])<'a' || strtolower($sl[$i][$j])>'f')) { $integer=false; $sl[$i]=substr($sl[$i],0,$j)."</span>".substr($sl[$i],$j,strlen($sl[$i])); $j+=7; continue; } if (substr($sl[$i],$j,2)=="/*" && !$c && !$s) $comment=true; else if (substr($sl[$i],$j,2)=="*/" && !$c && !$s && $comment) $comment=false; else if (substr($sl[$i],$j,6)==""" && !$c && ($sl[$i][$j-1]!="\\" || substr($sl[$i],$j-2,2)=="\\\\") && !$comment) { $s=!$s; if ($s) { $sl[$i]=substr($sl[$i],0,$j)."<span class=\"string\">".substr($sl[$i],$j,strlen($sl[$i])); $j+=21; } else { $sl[$i]=substr($sl[$i],0,$j+6)."</span>".substr($sl[$i],$j+6,strlen($sl[$i])); $j+=7; } } else if ($sl[$i][$j]=="'" && !$s && !$comment) { $c=!$c; if ($c) { $sl[$i]=substr($sl[$i],0,$j)."<span class=\"string\">".substr($sl[$i],$j,strlen($sl[$i])); $j+=21; } else { $sl[$i]=substr($sl[$i],0,$j+1)."</span>".substr($sl[$i],$j+1,strlen($sl[$i])); $j+=7; } } else if ($sl[$i][$j]=="#" && $e) { $sl[$i]="<span class=\"pre\">".$sl[$i]."</span>"; break; } else if (substr($sl[$i],$j,2)=="//" && !$comment && !$s && !$c) { $sl[$i]=substr($sl[$i],0,$j)."<span class=\"comment\">".substr($sl[$i],$j,strlen($sl[$i]))."</span>"; break; } if ($sl[$i][$j]!=" ") $e=false; } } $str=implode("",$sl); $str=str_replace("\n\n","\n",$str); $str=str_replace("\r\n","\n",$str); $str=str_replace("/*","<span class=\"comment\">/*",$str); $str=str_replace("*/","*/</span>",$str); return "<pre>".$str."</pre>"; } ?>
Und du musst diese einbinden und dann einfach code(cpp_code); aufrufen, wobei cpp_code ein Array ist. Die Styles für die Sachen Comment, String, etc. musst du selbst gestalten. Ich persönlich kommentiere solche Scripts nie... keine Lust
Aber ich denke mal, dass ein kurzer Blick auf php.net genügt um diesen Script zu verstehen.
-
Mein beitrag:
function code2($code) { // Array der Schlüsselwörter global $k; // Allgemeine Ersetzungen $code = str_replace('\t', ' ', $code); $code = htmlentities($code); // Kommentare capturen und durch tokens ersetzen $comment_cnt = preg_match_all('~(/\*.*?\*/)~s', $code, $comments_1, PREG_SET_ORDER) + preg_match_all('~(//.*)~', $code, $comments_2, PREG_SET_ORDER); if ($comment_cnt > 0) { $comments = array_merge($comments_1, $comments_2); foreach ($comments as $comment) { $code = str_replace($comment[1], md5($comment[1]), $code); } } // Strings capturen und durch tokens ersetzen $string_cnt = preg_match_all('~(".*?(?<!\\\\)")~s', $code, $strings, PREG_SET_ORDER); if ($string_cnt > 0) { foreach ($strings as $string) { $code = str_replace($string[1], md5($string[1]), $code); } } // Schlüsselwörter. $kw_preg = '~(?<![A-Za-z0-9_])(' . implode('|', $k) . ')(?![A-Za-z0-9_])~'; $code = preg_replace($kw_preg, '<span class="key">\\1</span>', $code); // Präprozessor. $code = preg_replace('~(#.*)~', '<span class="pre">\\1</span>', $code); // Zahlen. $code = preg_replace('~(^|[^+\-0-9\.a-zA-Z])([+\-0-9\.]+)([^+\-0-9\.a-zA-Z]|$)~', '\\1<span class="number">\\2</span>\\3', $code); // Kommentartokens zurückersetzen if ($comment_cnt > 0) { foreach ($comments as $comment) { $code = str_replace(md5($comment[1]), '<span class="comment">' . $comment[1] . '</span>', $code); } } // Stringtokens zurückersetzen if ($string_cnt > 0) { foreach ($strings as $string) { $code = str_replace(md5($string[1]), '<span class="string">' . $string[1] . '</span>', $code); } } return "<pre>$code</pre>"; }
Anmerkung: k** ist das Array mit den Schlüsselwörtern (siehe Windoofs Post). **code ist ein einzelner String.
-
Hi! Endlich hatte ich mal Zeit dafür, bei deinem Code traten Fehler auf, wie z.B. innerhalb eines Strings gab es Kommentare, etc. Jetzt geht es einigermaßen, mit der folgenden Funktion, aber da gibt es überall immernoch Schlüsselwörter... daran werd ich auch noch arbeiten. Danke aber für deine Funktion, probier mal diese:
<?php function code($code) { // Array der Schlüsselwörter $k=array( "AnsiString", "bool", "break", "byte", "case", "catch", "char", "class", "const", "continue", "delete", "do", "double", "dynamic_cast", "else", "extern", "false", "__fastcall", "__finally", "float", "for", "if", "int", "__int64", "long", "new", "operator", "private", "__property", "protected", "public", "__published", "return", "signed", "static_cast", "string", "String", "switch", "true", "try", "unsigned", "void", "while"); // Allgemeine Ersetzungen $code = str_replace('\t',' ',$code); $code = htmlentities($code); // Schlüsselwörter. $kw_preg = '~(?<![A-Za-z0-9_])(' . implode('|', $k) . ')(?![A-Za-z0-9_])~'; $code = preg_replace($kw_preg, '<span class="key">\\1</span>', $code); // Präprozessor. $code = preg_replace('~(#.*)~', '<span class="pre">\\1</span>', $code); // Strings capturen und durch tokens ersetzen $string_cnt = preg_match_all('~(".*?(?<!\\\\)")~s', $code, $strings, PREG_SET_ORDER); if ($string_cnt > 0) { foreach ($strings as $string) { $code = str_replace($string[1], md5($string[1]), $code); } } // Zahlen. $code = preg_replace('~(^|[^+\-0-9\.a-zA-Z])([+\-0-9\.]+)([^+\-0-9\.a-zA-Z]|$)~', '\\1<span class="number">\\2</span>\\3', $code); // Kommentare capturen und durch tokens ersetzen $comment_cnt = preg_match_all('~(/\*.*?\*/)~s',$code,$comments_1,PREG_SET_ORDER) + preg_match_all('~(//.*)~',$code,$comments_2,PREG_SET_ORDER); if ($comment_cnt > 0) { $comments = array_merge($comments_1, $comments_2); foreach ($comments as $comment) { $code = str_replace($comment[1], md5($comment[1]), $code); } } // Kommentartokens zurückersetzen if ($comment_cnt > 0) { foreach ($comments as $comment) { $code = str_replace(md5($comment[1]), '<span class="comment">' . $comment[1] . '</span>', $code); } } // Stringtokens zurückersetzen if ($string_cnt > 0) { foreach ($strings as $string) { $code = str_replace(md5($string[1]), '<span class="string">' . $string[1] . '</span>', $code); } } return "<pre>$code</pre>"; } ?>
-
Du hast recht, ich habe die Funktion dann im Nachhinein nocheinmal optimiert. So dürfte alles funktionieren:
<?php $k_cpp = Array( 'AnsiString', 'bool', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'extern', 'false', '__fastcall', '__finally', 'float', 'for', 'if', 'int', '__int64', 'long', 'new', 'operator', 'private', '__property', 'protected', 'public', '__published', 'return', 'signed', 'static_cast', 'string', 'String', 'struct', 'switch', 'true', 'try', 'typedef', 'unsigned', 'void', 'while' ); $highlight_data_cpp = 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_cpp) . ')(?![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="number">%s</span>') ); function code3($code, $highlight_data) { $code = htmlentities($code); 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>"; } ?>
Dadurch dass jetzt alles durch Tokens ersetzt wird, gibt es keine Schlüsselwörter in Kommentaren und so weiter. Es kommt aber auf die Reihenfolge der Arrayelemente an. Außerdem habe ich versucht, dass selbe Prinzip für PHP umzusetzen bin aber an den unterschiedlichen Möglichkeiten für Stringdelimiter gescheitert. Bin für weitere Vorschläge aber stets offen.
-
Ich schreibe im Moment auch so eine Funktion. Der Schwerpunkt liegt einfach daran, daß man einen Code nicht zig mal mit unterschiedlichen Filtern durchlaufen soll, sondern falls was gefunden wurde - gleich außen vor lassen und die übrigen Stellen weiter durchsuchen.
Betrachten wir diesen Code:// Kommentar /* Hier neuer Kommentar(?)*/
In diesem Fall muss man einfach gucken, ob // oder /* zuerst auftaucht, entsprechend handeln und die Stelle (Anfang - Ende) vermerken. Außer /* und // kann es noch "", '' und den #prepr geben, da könnte z.B. min() helfen, die richtige Wahl zu treffen.
Ich hoffe geholfen zu haben.
@Dasd deine Methode ist zu kompliziert und auch recht langsam, man kommt ohne Regex aus, wenn man meinen Vorschlag in Betracht zieht.
-
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.