kostenloser Webspace werbefrei: lima-city


preg_replace_callback problem

lima-cityForumProgrammiersprachenPHP, MySQL & .htaccess

  1. Autor dieses Themas

    willstdueswissen

    Kostenloser Webspace von willstdueswissen

    willstdueswissen hat kostenlosen Webspace.

    Also ich habe ein regex der bei preg_match_tag/all">all alles richtig macht http://www.phpliveregex.com/p/547
    Jetzt habe ich mir eine function geschrieben mit preg_replace_callback: http://paste42.de/6938/minecraftcolor_to_html
    Es geht um die preg_replace_callback Funktion mit dem switch case drin, die andere funktioniert.

    (minecrafttohtml())
    Hier erkennt er nicht mehr den ganzen Satz nur ein Teil:
    http://willstdueswissen.de/battlecraftonline/?sites=der_server
    (Ein Teil wird mit base64 verschlüsselt, der Rest ist normal)

    Danke für die Hilfe

    Beitrag zuletzt geändert: 30.4.2014 20:22:51 von willstdueswissen
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Es wäre nett gewesen, wenn du uns mitgeteilt hättest, was du da eigentlich bauen möchtest. Ein eher wenig übersichtliches Stück preg_replace_callback()-Code mit einem weiteren darin verschachteltem preg_replace_callback()-Code ist an sich schon nicht einfach zu debuggen. Ohne konkrete Funktionsbeschreibung macht es gar keinen Spaß mehr.

    Ich gehe jetzt davon aus, dass du irgendwelche Minecraft-Format-Codes in HTML umsetzen möchtest. Leider ist das Format etwas spärlich dokumentiert. Die einzige Referenz, die ich finden konnte, war die hier: http://minecraft.gamepedia.com/Formatting_codes
    Nur werde ich nicht schlau daraus, wie die Syntax exakt aufgebaut ist. Beispielsweise lassen sich Farbe ('0'...'9', 'a'...'f') und Stil ('l'...'o') verschachteln, wenn die Farbe zuerst gesetzt wird. Umgekehrt geht es nicht, da das Setzen einer Farbe den Stil komplett zurücksetzt. Wer denkt sich solch einen inkonsistenten Quark aus? Es ist auch nicht ersichtlich, ob sich Stile selbst kombinieren lassen (bei Farben geht das offensichtlich gar nicht erst).

    Jedenfalls kommt man da mit einer einfachen Callback-Funktion nicht weit, weil irgendwo der aktuelle Zustand ("state") der Formatierung gespeichert werden muss, sonst erzeugt man unter Umständen ungültiges HTML (weil schließende Tags fehlen). Du brauchst also eine externe Variable: Die gibts mit use(), falls du unbedingt auf PHP-Closures zurückgreifen möchtest. Einfacher finde ich es, ein Objekt und dessen Member-Variablen zu benutzen.

    Weiterhin muss Text, der in HTML eingebaut werden soll, von entsprechenden Steuerzeichen befreit werden (siehe: htmlspecialchars()). Das geht nur, wenn der Reguläre Ausdruck, den preg_replace_callback() benutzt, alle Zeichen des Textes erfasst und nicht nur die Steuercodes. Die Callback-Funktion muss also mehrere Zustände erkennen können: Text(anfang) ohne Steuercodes, Text-Ende und Steuercode + zu formatierender Text. Entsprechend umständlich muss der Reguläre Ausdruck konstruiert werden. Deswegen hab ich ihn über mehrere Zeilen verteilt und mit Kommentaren versehen.

    Also habe ich mal etwas zusammengeschraubt:

    // a simple minecraft format code to html converter
    class minecraftformat {
    
        const version = '$VER: minecraft-format-to-html-converter 0.1 (2014-05-01)';
    
        function __construct() {
            $this->init();
        }
    
        function init() {
            $this->default_color = 0; // default color code
            $this->styles = array (); // reset-codes for all the previously set text styles
        }
    
        // convert minecraft format codes into html
        function as_html(
            $mc // minecraft formatted text
        ) {
            $this->init();
            return preg_replace_callback(
                '/(?:
                    (?:
                        \A # start of string (to catch text before 1st format code)
                    |
                        §([0-9a-fk-or]) # (1) format codes
                    )
                    ([^§]*)          # (2) raw text
                |
                    (\z) # (3) end of string
                )/x',
                array ($this, 'callback'),
                $mc
            );
        }
    
        function callback(
            $h // array() of hits generated by preg_replace_callback()
                // $h[1] format code
                // $h[2] raw text; signals start of text if empty
                // $h[3] signals end of string
        ) {
            $fmt = $h[1]; // the format code
            $out = ''; // the html output string
    
            // end of string or reset code
            if (isset ($h[3]) || 'r' === $fmt) {
                // reset all previously set styles
                while ($reset = array_pop($this->styles)) {
                    $out .= $reset;
                }
                // reset (foreground) color
                $out .= $this->format('/', 'span');
                if ('r' === $fmt) {
                    $out .= $this->format('', $this->color($this->default_color));
                }
            }
            // start of string without a format code
            elseif (!isset ($fmt[0])) {
                // init (foreground) color
                $out .= $this->format('', $this->color($this->default_color));
            }
            // color format code ('0'...'9', 'a'...'f')
            elseif ($fmt <= 'f') {
                // reset all previously set styles
                while ($reset = array_pop($this->styles)) {
                    $out .= $reset;
                }
                // reset previous (foreground) color
                $out .= $this->format('/', 'span');
                // set new (foreground) color
                $out .= $this->format('', $this->color($fmt));
            }
            // style format codes (except 'r')
            else {
                // set new style
                $style = $this->style($fmt);
                $this->styles[] = $this->format( '/', $style);
                $out .= $this->format('', $style);
    
                // special treatment for the "obfuscate" format code
                if ('k' === $fmt && method_exists($this, 'obfuscate')) {
                    $h[2] = $this->obfuscate($h[2]);
                }
            }
            return $out . htmlspecialchars($h[2]);
        }
    
        // create a html-tag
        function format(
            $end = '', // either '' or '/'
            $element = 'span', // html element name (+ optional attributes)
            $attrib = '' // attributes to include
        ) {
            return sprintf(
                '<%s%s%s>',
                $end,
                '/' === $end ? strtok($element, ' ') : $element,
                $attrib
            );
        }
    
        // get a html tag specifying a css-style color from a minecraft color format code
        function color(
            $what
        ) {
            static $col = array (
                0 => '#000000',
                '#0000aa',
                '#00aa00',
                '#00aaaa',
                '#aa0000',
                '#aa00aa',
                '#ffaa00',
                '#aaaaaa',
                '#555555',
                '#5555ff',
                'a' => '#55ff55',
                'b' => '#55ffff',
                'c' => '#ff5555',
                'd' => '#ff55ff',
                'e' => '#ffff55',
                'f' => '#ffffff',
            );
            return isset ($col[$what])
                ? sprintf('span style="color: %s;"', $col[$what])
                : 'span';
        }
    
        // get the html tag for a minecraft style format code
        function style(
            $what
        ) {
            static $fmt = array (
                'k' => 'sup', // obfuscated
                'l' => 'b',
                'm' => 'span style="text-decoration: line-through;"', // <s> is deprecated
                'n' => 'u',
                'o' => 'i',
            );
            return isset ($fmt[$what])
                ? $fmt[$what]
                : 'span';
        }
    
        // implement your obfuscating function here
        function obfuscate($raw) {
            return str_rot13($raw);
        }
    }


    Das alles lässt sich sicher noch verbessern. Beispielsweise könnte man die Anzahl der Span-Tags für die Farb-Umschaltung verringern. Aber erstmal funktioniert es, wie man an ein paar Tests sehen kann:

    // usage (Anwendung):
    
    $tests = array (
        '<b>bold if not escaped</b> §l§mcombined §ostyles §5color resets style, §nbut stays if noted after style',
    
        '§k§a#1 §6Hardcore §aEconomy §6Server! §7||§2Rising Map Released§7|| §e**Brand New World**',
    
        // see: http://minecraft.gamepedia.com/Formatting_codes#Example_Text
        '§nMinecraft Formatting
    
        §r§00 §11 §22 §33
        §44 §55 §66 §77
        §88 §99 §aa §bb
        §cc §dd §ee §ff
    
        §r§0k §kMinecraft
        §rl §lMinecraft
        §rm §mMinecraft
        §rn §nMinecraft
        §ro §oMinecraft
        §rr §rMinecraft',
    );
    
    $mcf = new minecraftformat();
    
    foreach ($tests as $mc_formatted_text) {
        $html = $mcf->as_html($mc_formatted_text);
        // raw text :: html output :: html source
        printf("\r\n<br />:: %s \r\n<br />:: %s \r\n<br />:: %s \r\n<br />", htmlspecialchars($mc_formatted_text), $html, htmlspecialchars($html));
    }


    Beitrag zuletzt geändert: 1.5.2014 23:57:03 von alopex
  4. Autor dieses Themas

    willstdueswissen

    Kostenloser Webspace von willstdueswissen

    willstdueswissen hat kostenlosen Webspace.

    Hallo alopex,
    danke für die riesige Antwort und super Antwort.
    Du hättest nicht unbedingt für uns eine komplette Funktion schreiben müssen.
    Meine zwei verschachtelten preg_replace_callbacks haben schon ziemlich gut funktioniert und waren ja auch noch nicht ganz fertig (waren noch in Arbeit, wobei ich das eine Problem nicht lösen kann, der Rest weiß ich eigentlich schon in etwa wie ich es lösen kann)
    Das Problem, das ich hatte habe ich nun selber versucht zu lösen.
    Da habe ich festgestellt das, dass regex nicht richtig funktioniert.
    Wie in meinem live regex Beispiel funktionierte, funktionierte es in preg_replace_callback nicht ganz.
    Ich habe per print_r die variable ausgeben lassen.
    Der Text der selektiert wurde ging nur bis zu den ||.
    Das wüsste ich gerne Warum das bei preg_replace_callback anders ist als bei preg_match.
    Wenn du uns den Code frei zur Verfügung stellst würden wir ihn auch gerne ausprobieren.
    Dennoch wurde ich gerne die Lösung meines Problems haben, man möchte ja noch lernen, wenn etwas nicht richtig funktioniert.

    Danke noch mal für die Antwort.
  5. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!