Klammern und Kommas im String sollen zu einer Liste führen

Alles rund um die Programmierung mit Qt
Antworten
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Klammern und Kommas im String sollen zu einer Liste führen

Beitrag von feldmaus »

Guten Morgen,

ich versuche mit dem folgenden Code einen QString in ein QList zu überführen. Als Beispiel soll "(das) Essen" zu ["das Essen", "Essen"] führen, oder "eine Menge, viel" soll zu ["eine Menge", "viel"] führen.

Mein derzeitiger Code ist leider nicht flexibel genug, soll heißen es wird nur ein einfacher Klammer-Ausdruck berücksichtigt, wenn ich allerdings z.b. "(o, a) tenista" habe versagt mein Code, da in der Klammer ein Komma ist, was mein Code falsch interpretieren würde. Wünschen würde ich mir das mein Code mit EINEM Klammer-Ausdruck und mit beliebig vielen Kommas in diesem Klammer-Ausdruck klar kommt. Außerhalb von Klammer-Ausdrücken sind ja beliebig viele Kommas erlaubt.

Hier mein jetziger Code:

Code: Alles auswählen

void KEduVocText::setList( const QString & expr )
{
    Qlist liste = expr.simplified().split(",", QString::SkipEmptyParts);
    QList modListe;
    foreach(Qstring str, liste) {
        if ( str.contains( QRegExp("\(.*\)") ) ) {
            modListe << str.replace( QRegExp("\(([^<]*)\)"), "" ).simplified()
                            << str.replace( QRegExp("\(([^<]*)\)"), "\\1" ).
                                 simplified();
        }
        else {
            modListe << str;
        }
    }
    d->m_list = modListe;
}
Grüße Markus

EDIT: Der Ausdruck "expression1 (irgendwas, weiter was) expression2", sollte auch zu einem korrektem Ergebnis führen.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

selbst ohne Code faellts mir schwer, eindeutige Ergebnisse vorherzusagen :-)
was soll zum beispiel bei "(eine) Menge, viel" rauskommen ?

Ich versteh das prinzip noch ned ganz ^^

keine Ahnung, ob sich das durch regexp loesen laesst.

Und wenn DU mit RegExp nicht weiter kommst, wirst du wohl tiefer in die stringinterpretation einsteigen muessen. Sowas wie eine Art Programmiersprache schreiben.

Such mal nach Token Tokenizer, da solltest vielleicht Ansatzpunkte finden.

Ciao ...
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Beitrag von feldmaus »

RHBaum hat geschrieben:was soll zum beispiel bei "(eine) Menge, viel" rauskommen ?
Ergebnis: ["eine Menge", "Menge", "viel"]

Die Wörter in Klammern sind immer optional und können, müssen aber nicht, zum korrekten Ergebnis führen.

Hintergrund ist eine Vokabel-Software in der die vom Benutzer eingegebenen Wörter auf Richtigkeit geprüft werden.

Grüße Markus
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Beitrag von feldmaus »

EDIT: DER CODE ist hier

So habe meinen Code ausgebessert, allerdings noch ungetestet. kdevelop highlighted aber alle wörter, also ist auch alles deklariert.

Mein Code enthält zwei ineinander verschachtelte Schleifen, leider weiß ich nicht wie ich es sonst vermeiden kann. Die zu verarbeitenden Zeichenketten sind aber nicht lang. Vielleicht hat der eine oder andere noch Tuning Ideen, Schönheitskorrekturen oder findet Fehler.

Code: Alles auswählen

void KEduVocText::setList( const QString & expr )
{
    QStringList liste = expr.simplified().split(",", QString::SkipEmptyParts);
    QStringList modListe;
    foreach (QString str, liste) {
        if ( str.contains( QRegExp("\(.*\)") ) ) {
            QStringList bracketExpr = str
                                                       .section( QChar::Mark_Enclosing, 1, 1 )
                                                       .split( ",", QString::SkipEmptyParts );
            for ( int i; i < bracketExpr.size(); ++i ) {
                bracketExpr[i] = bracketExpr[i].simplified();
            }
                                      
            QStringList nonBracketExpr = str.replace( QRegExp("\(.*\)"), "," )
                                                                 .split( "," ) ;
            nonBracketExpr[0] = nonBracketExpr[0].simplified();
            nonBracketExpr[1] = nonBracketExpr[1].simplified();
            QString pre = nonBracketExpr[0] , post = nonBracketExpr[1];
            foreach ( QString elem,  bracketExpr ) {
                modListe << pre+elem+post;
            }
            modListe << pre+post;
        }
        else {
            modListe << str;
        }
    }
    d->m_list = modListe;
}
Am liebsten würde ich diesen Code noch dokumentieren, weiß aber nicht ob das Gut ist in einem so großen Programm (parley) was rein zu schreiben. Was meint Ihr? Und wenn dokumentieren, dann wie?

Grüße Markus
Zuletzt geändert von feldmaus am 17. Juni 2011 12:59, insgesamt 2-mal geändert.
kater
Beiträge: 306
Registriert: 29. Dezember 2009 01:13
Wohnort: Darmstadt

Beitrag von kater »

Na so schwer ist das doch nicht. Hast ein guten Anfang. Problem ist, dass du nicht mit split den String anhand den Kommas trennen kannst. Da auch Kommas in Klammern vorkommen.

Regex kann ich leider auch nicht. Daher durchlaufe den String doch einfach von Hand von links nach rechts. Merke dir die Positionen der Kommas, wenn sie nicht nach einer offenen Klammer stehen.
Also einfach merken. Offene Klammer gefunden ja/nein. Komma Position merken ja/nein.
Dann kannst du den String zerlegen.
Und mit den Teilstücken machst du weiten. Keine Kammer im Teilstück vorhanden? -> Ferig. Wenn nicht, Teilstück weiter zerlegen. Da funktioniert dann die split() Funktion gut.

So, oder so ähnlich jedenfalls :)
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Beitrag von feldmaus »

Mein kdevelop meckert rum, dass QRegExp() mit meinem Klammer-Zeichen nicht klar kommt.

Wie müsste ich QRegExp() eine Klammer als Zeichen übergeben?

Code: Alles auswählen

QRegExp("\\(.*\\)")
oder

Code: Alles auswählen

QRegExp("\\\(.*\\\)")
oder
...???

Laut QT Doku von QRegExp muss ich "\\\(" schreiben, also drei mal Backslash. Ich bekomme aber vom Compiler eine Warning unknown escape sequence: '\)'.
sowas
Beiträge: 105
Registriert: 19. September 2006 16:02

Klammern und Kommas im String sollen zu einer Liste führen

Beitrag von sowas »

Hallo,
mit QRegExp() kenne ich mich nicht aus. Ich würde es so lösen.
Wenn es geht, den Text mehrmals parsen, zuerst nach Klammern suchen, wenn es welche gibt, feststellen ob zwischen den Klammern Kommata stehen, diese würde ich z.B. durch eine Raute '#' ersetzen. Beim nächsten Durchgang stören die Kommata nicht mehr.
Zum Schluss die Rauten löschen oder durch andere Zeichen ersetzten.
bk
FaS
Beiträge: 184
Registriert: 25. Mai 2006 19:48
Kontaktdaten:

Beitrag von FaS »

@sowas: mit einem anderen Zeichen ersetzen> Nein, das würde unnötige Ausnahmeregelungen erfordern.

@feldmaus: \ Ist ein Escape-Zeichen in C-Strings, das hat nichts mit Qt zu tun! QRegExp braucht \( und \ schreibt man in C++ '\\', also musst du im Code "\\(" stehen haben.

Tuning-Ideen> Nicht QRegExp verwenden, so ähnlich vorgehen wie kater beschrieben hat, einfach von links nach rechts durchgehen:
- klammer auf? pre speichern
- klammer zu? klammerinhalt in liste speichern
- komma oder string-ende erreicht? post speichern; klammerinhalt leer? post in die ergebnisliste packen, ansonsten klammerinhalt durchgehen und zusammen mit pre und post in die ergebnisliste packen

Gruß
FaS
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Beitrag von feldmaus »

Danke,

ich komme gerade nicht weiter. Ich will das doch so machen wie ursprünglich überlegt. In meiner Funktion nutze ich QStringList.section( QChar::Mark_Enclosing, 1, 1 ) um die Klammerausdrücke zu selektieren. Nun macht er dies nicht, in der QT-Doku steht nicht welche Zeichen mit Mark_Enclosing gemeint sind. Kann mir das Jemand verraten?

Grüße Markus
feldmaus
Beiträge: 32
Registriert: 25. September 2007 21:08

Beitrag von feldmaus »

FaS hat geschrieben:\ Ist ein Escape-Zeichen in C-Strings, das hat nichts mit Qt zu tun! QRegExp braucht \( und \ schreibt man in C++ '\\', also musst du im Code "\\(" stehen haben.
Wenn ich das Whitespace Zeichen nutzen will '\s' muss ich dann auch '\\s' schreiben?

Irgendwie schaffe ich es nicht eine korrekte Liste aus z.b. '(o, a) tenista' zu erhalten. Die Liste die er mir gibt sieht wie folgt aus ["(", "a) tenista"]. Ich habe als Befehl folgenden verwendet:

Code: Alles auswählen

    QStringList liste = expr.simplified().split(QRegExp("([^\\(][.\\s]*),"),
                                                                      QString::SkipEmptyParts);
Dabei soll QRegExp nur Kommas ausserhalb von Klammern selektieren.

Grüße Markus
FaS
Beiträge: 184
Registriert: 25. Mai 2006 19:48
Kontaktdaten:

Beitrag von FaS »

Entschuldige meine späte Antwort.
QChar::Mark_Enclosing
Das ist eine Unicode-Kategorie, also nicht was du suchst, Google "Mark Enclosing", erstes Ergebnis. Aber hast du dann wohl selbst gemerkt.

Code: Alles auswählen

split(QRegExp("([^\\(][.\\s]*),")
Die Klammern sollten hier überflüssig sein, da keine capturing groups benötigt werden. Also wird Qt in diesem Kontext logsich äquivalent folgendes übergeben:

Code: Alles auswählen

[^\(][.\s]*,
Wörtlich: (ein Zeichen != Klammer auf), (kein Zeichen oder beliebiger white space), (Komma). Dies trifft auf "o," zu, also diente das in deinem Beispiel als Trenner. Komplexere Selektionen scheinen mit split() nicht möglich.

Ich empfehle immernoch meinen genannten Ansatz, das ist viel einfacher als mit regulären Ausdrücken herumzuwurschteln, und schneller obendrein.
Troll.Soft
Beiträge: 190
Registriert: 18. Juni 2008 09:52
Wohnort: Hamburg

Beitrag von Troll.Soft »

moin auch,
ich denke, der von Sowas weiter oben erwähnte Ansatz führt am leichtesten zum Ziel.
tschüß
Troll.Soft
Antworten