2012-03-27 11 views
0

Ich vergesse reguläre Ausdrücke schneller als der Geburtstag meiner Mutter. Es ist eine wichtige PITA. Jedenfalls wollte ich einen RE für das Parsen der HTTP-Response-Statuszeile und das korrekte Erfassen der Unterelemente. Ich habe diese Arbeit:Tokening Text mit Boost Regex

const boost::regex status_line("HTTP/(\\d+?)\\.(\\d+?) (\\d+?) (.*)\r\n"); 
    std::string status_test1("HTTP/1.1 200 hassan ali\r\n"); 

    boost::smatch what; 
    std::cout << regex_match(status_test1,what, status_line, boost::match_extra) << std::endl; 
    std::cout << what.size() << std::endl; 

    BOOST_FOREACH(std::string s, what) 
    { 
    std::cout << s << std::endl; 
    } 

Die 4. Capture-Gruppe ist es, was ich war Getue, vor allem die Worte tokenising. Aber ich brauche es nicht, also ist meine Arbeit erledigt. Allerdings möchte ich immer noch wissen, wie man einen durch Leerzeichen getrennten Satz, der mit einem '\ 0' endet, in einen Vektor/ein Array von entfernten Wörtern zerlegt.

kann ich nicht bekommen das folgende Fragment

const boost::regex sentence_re("(.+?)((.+?))*"); 
    boost::smatch sentence_what; 
    std::string sentence("hassan ali syed "); 

    std::cout << boost::regex_match(sentence,sentence_what,sentence_re, boost::match_extra) << std::endl; 

    BOOST_FOREACH(std::string s, sentence_what) 
    { 
    std::cout << s << std::endl; 
    } 

es nicht "hassan ali syed " übereinstimmen sollten arbeiten, aber es sollte "hassan ali syed" übereinstimmen, und die Capture-Gruppe ausgeben sollte hassanalisyed (mit Zeilenumbrüchen), aber es Ausgänge hassansyedsyed (beachten Sie, der Raum in der dritten syed <space>syed. ich nehme an Einfanggruppen nicht mit rekursiven Entitäten umgehen können?

Gibt es also eine saubere Möglichkeit, eine Token-Task in der PCRE-Syntax anzugeben, die zu einem sauberen Token-Vektor führt (ohne Wiederholung - z. B. möchte ich nicht, dass die verschachtelte Gruppe versucht, den Leerraum zu streichen).

Ich weiß, dass dies nicht das richtige Werkzeug für den Job ist, spirit/lexx oder boost :: tokenise ist am besten, und ich weiß, dass es nicht der richtige Weg ist. In .net, wenn ich Screen Scraping durchführe, würde ich Token in Textkörpern finden, indem ich wiederholt einen regulären Ausdruck auf den Körper anwende, bis ihm die Token ausgehen.

Antwort

1

Das erinnert mich an eine ähnliche Frage, Capturing repeating subpatterns in Python regex.

Wenn die Anzahl der durch Leerzeichen getrennte Wörter ist bis zu einem gewissen maximalen Anzahl von Token begrenzt, dann können Sie nur auf eine ganze Reihe von zusätzlichen Subpattern tack, etwa wie:

"HTTP/(\\d+?)\\.(\\d+?) (\\d+?) ([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?([^ ]+\s)?\n\r" 

Was natürlich ist, schrecklich .

Wenn Sie eine verschachtelte Gruppe wollte ich nicht denken dies ohne „wiederholte Unter-Pattern“ Unterstützung in Ihrer regexp Implementierung durchgeführt werden (siehe Python Nicht-Standard-regex Modul in der verknüpften Frage verwendet.) Sie sind fast sicher besser machen Sie dies mit elementaren String-Funktionen - Ihre lokale Entsprechung von string.split().

+0

Hinweis: Ich bin kein C++ oder boost :: regexp Benutzer. –

0

Boost könnte rekursive Gruppierungen durchführen, nicht sicher. Ich lehne mich darauf hin, dass es nicht geht.
Ich kenne nur .NET, die das tun können.

Sie können eine einzelne Regex mit zwei Teilen entwerfen. Der erste Teil erfasst bestimmte Gruppen, der zweite Teil erfasst den Rest in einer einzigen Gruppe. Sie können dann einen weiteren rekursiven Regex für den zweiten erfassten Teil ausführen.

Etwas wie folgt aus:
(specific)(part)(to)(capture)(all the remaining text)

Dann eine Weile tun (/ (Teil) /) regex auf der vorherigen verbleibenden Texterfassung.

Hier ist, wie Sie es im Boost tun könnte -

const string status = "HTTP/1.1 200 hassan ali\r\n"; 

boost::regex rx_sentence ("HTTP/(\\d+)\\.(\\d+)\\s+(\\d+)\\s*([^\\s]+(?:\\s+[^\\s]+)*)?.*"); 
boost::regex rx_token ("[^\\s]+"); 

if (boost::regex_match(status, what, rx_sentence)) 
{ 
    std::cout << "\nMatched:\n-----------------\n" << "'" << what[0] << "'" << std::endl; 

    std::cout << "\nStatus (match groups):\n-----------------" << std::endl; 
    for (int i=1; i < 4; i++) 
    { 
     std::cout << i << " = '" << what[i] << "'" << std::endl; 
    } 
    std::cout << "\nTokens (search of group 4):\n-----------------" << std::endl; 
    const string token_str = what[4]; 

    std::string::const_iterator start = token_str.begin(); 
    std::string::const_iterator end = token_str.end(); 

    while (boost::regex_search(start, end, what, rx_token)) 
    { 
     string token(what[0].first, what[0].second); 
     cout << "'" << token << "'" << endl; 
     start = what[0].second; 
    } 
} 
else 
    std::cout << "Didn't match" << std::endl;