Seite 1 von 1

[gelöst] Syntax Highlighter für PHP mit sehr vielen Keywords

Verfasst: 2. Juni 2011 17:39
von B.C.
Hi,

ich bin gerade dabei, neben dem HTML-Highlighter jetzt einen PHP-Highlighter zu schreiben. Dafür habe ich alle php funktionen, konstanten und ähnliches in verschiedene Text-Dateien gepackt, die ich im Quellcode dann gezielt färben möchte. Wenn ich Funktionen + Kontroll Strukuren färben lasse, funktioniert alles wunderbar. Sobald ich allerdings die Konstanten (nochmal 1000+ Wörter) hinzunehme, hängt sich das Programm sofort auf, wenn ich nur eine Eingabe ins Textfeld mache. Wie kann ich das performancegünstiger machen? Hier der jetzige Quellcode

Code: Alles auswählen

#include "phphighlighter.h"

#include <QFile>
#include <QTextStream>

PhpHighlighter::PhpHighlighter(QTextDocument *document) : QSyntaxHighlighter(document)
{
    HighlightingRule rule;

    /*
     * Control Structures like
     * if, else, switch ...
     */
    controlStructuresFormat.setForeground(QColor(161, 161, 0));
    QFile file(":/Keywords/php_control_structures.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream in(&file);
    while(!in.atEnd()) {
        rule.pattern = QRegExp("\\b" + in.readLine() + "\\b");
        rule.format = controlStructuresFormat;
        highlightingRules.append(rule);
    }

    /*
     * All in PHP predeclared functions
     */
    functionsFormat.setForeground(QColor(100, 74, 155));
    QFile file2(":/Keywords/php_functions.txt");
    if (!file2.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream in2(&file2);
    while(!in2.atEnd()) {
        rule.pattern = QRegExp("\\b" + in2.readLine() + "\\b");
        rule.format = functionsFormat;
        highlightingRules.append(rule);
    }

    constantsFormat.setFontWeight(QFont::Bold);
    QFile file3(":/Keywords/php_constants.txt");
    if (!file3.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream in3(&file3);
    while(!in3.atEnd()) {
        rule.pattern = QRegExp("\\b" + in3.readLine() + "\\b");
        rule.format = constantsFormat;
        highlightingRules.append(rule);
    }
}

void PhpHighlighter::highlightBlock(const QString &text)
{
    foreach (const HighlightingRule &rule, highlightingRules) {
        QRegExp expression(rule.pattern);
        int index = expression.indexIn(text);
        while (index >= 0) {
            int length = expression.matchedLength();
            setFormat(index, length, rule.format);
            index = expression.indexIn(text, index + length);
        }
    }

    setCurrentBlockState(0);
}
Gruß,
Basti

Verfasst: 2. Juni 2011 18:21
von upsala
Nur ein paar RegEx zusammenbauen und sämtliche Schlüsselwörter in ein QSet packen.

Verfasst: 2. Juni 2011 19:07
von B.C.
In ein QSet packen ist nicht schwer. Aber wie prüfe ich die jetzt nun alle durch? Wie sieht das am Ende aus?

Verfasst: 2. Juni 2011 21:14
von upsala
Bau dir eine RegEx die für alle Keywords gültig ist. Alle Keywords fangen mit einem Buchstaben an, gefolt von x Buchstaben/Zahlen. Wenn diese RegEx matched dann brauchst du blos noch im QSet nachsehen.

Verfasst: 2. Juni 2011 21:23
von B.C.
Ja gute Idee, ich setz mich denn mal dran

Verfasst: 2. Juni 2011 23:24
von B.C.
Der reguläre Ausdruck findet immer nur das erste Vorkommen in der Zeile, Ergebnis sieht dann so aus:

Bild

Hier der Code dazu:

Code: Alles auswählen

void PhpHighlighter::highlightBlock(const QString &text)
{
    QRegExp expression("\\b[a-z]+\\b");
    int index = expression.indexIn(text);
    int i = 0;
    while(index >= 0)
    {
        int length = expression.matchedLength();

        if(controlStructures.contains(expression.cap(i)))
            setFormat(index, length, controlStructuresFormat);

        index = expression.indexIn(text, index + length);
        ++i;
    }

    setCurrentBlockState(0);
}
controlStructures ist ein QSet, das Wörter wie if, else, endif usw. enthält.
Was stimmt da mit dem regulären Ausdruck nicht? Ich habs online getestet und da ging alles bestens ...

Verfasst: 3. Juni 2011 15:59
von B.C.
Ich hab mir mal die Doku von QRegExp::cap() genauer angeschaut und da liegt der Fehler. Ich muss immer cap(0) benutzen, um an das Wort zu kommen. Den Integer i kann ich damit weglassen.