2009-07-11 4 views
1

Ich verstehe es nicht. Ich habe diese regulären Ausdruck:Boost :: Regex Problem, Matching ein HTML-Span-Element

 
<span class="copy[Green|Red].*>[\s]*(.*)[\s]*<\/span> 

bestimmte Teile von HTML-Code (ein Teil zwischen Spannweiten) übereinstimmen. Zum Beispiel die folgende:

 
<span class="copyGreen">0.12</span> 
<span class="copyRed"> 0.12 </span> 

Nun, das schön mit RegexBuddy arbeitet und andere, aber mit boost :: regex Ich habe ein Problem. Es passt nicht zusammen.

EDIT: Um genauer zu sein, möchte ich die Zahl zwischen den Spannen erfassen. Vor und nach der Nummer kann es auch Leerzeichen geben (\ n, \ r, etc.).

Hier ist der Code, den ich gemacht habe:


try { 
     const boost::regex e("<span class=\"copy[Green|Red].*>[\\s]*(.*)[\\s]*<\\/span>"); 
     boost::smatch matches; 
     std::string html("<span class=\"copyGreen\"> 0.12 </span>"); 

     if (boost::regex_match(html, matches, e)) { 
       // Works... (not). 
     } else { 
       throw std::runtime_error("Couldn't match the regex against HTML-source!"); 
     } 
} catch (boost::regex_error& e) { 
     std::cout << e.what() << std::endl; 
} 

Was mache ich falsch hier? Danke im Voraus!

EDIT:

Es scheint, dass der richtige Ausdruck würde

boost::regex("<span class=\"copy(?:Green|Red)[^>]*>\\s*(.*?)\\s*<\\/span>"); // Thanks chaos!.

sein Dies ist eigentlich mit Boost-Spiele auf. Allerdings musste ich boost :: match_extra aktivieren, um alle Captures zu erhalten, die ich brauchte. Dies geschah durch die Definition

BOOST_REGEX_MATCH_EXTRA

in boost \ regex \ user.hpp

Danke noch einmal.

Antwort

2

Zum einen ist dies:

[Green|Red] 

macht nicht das, was Sie denken, es tut. Sie wollen:

(?:Green|Red) 

[Green|Red] ist eine Zeichenklasse der Buchstaben aus GRred|, nicht eine Art und Weise zwischen den Spielen von abwechseln. So wie Sie es geschrieben haben, wird es genau einem dieser Zeichen folgen, gefolgt von einer beliebigen Anzahl anderer Zeichen.

Dies:

[\s] 

ist überflüssig und vielleicht gefährlich (je nach Auslegung könnte es sein, was tatsächlich machen Ihr Spiel nicht funktioniert). Es kann nur

\s 

Um Ihre \s Sekunden zu arbeiten, der Capturing-Ausdruck muss wahrscheinlich

(.*?) 

ich auch Ihre ersten .* in [^>]* machen empfehlen sein, das Problem, das Sie‘zu vermeiden Ich werde bekommen, wenn Sie jemals dies auf tatsächliche HTML-Dokumente anwenden, wo es willkürliche Mengen von HTML saugen wird.

+0

Umm .. sollte es nicht mit copyGreen oder copyRed übereinstimmen? Ich glaube nicht, dass ich falsch liege .. Bitte erklären Sie ein bisschen weiter, was und warum ich falsch mache. Vielen Dank. – nhaa123

+0

Eckige Klammern stehen für eine Übereinstimmung mit einem Zeichen. Das ist [grün | rot] ist identisch mit [gren | d] - es entspricht g OR r OR e OR n OR | ODER d.Bei Zeichenfolgen möchten Sie eine Alternierung, die in Klammern gruppiert werden muss, um zu verhindern, dass sie auf den gesamten Ausdruck angewendet wird. –

+0

Hah, OK. Ich stehe korrigiert, mein Entschuldigung;) – nhaa123

1

Es gibt ein paar Probleme mit Ihrer Regex.

Zunächst ist dieses Bit: [Green|Red]

, die einen Satz von Zeichen maches, das gesetzt ist G, r, e, n, |, R und d.

müssen Sie dies unter Verwendung von Parenthises tun, wie (Green|Red). jetzt entspricht dies entweder der Zeichenfolge Green oder Red.

BEARBEITEN: Wenn Sie nicht möchten, dass dies etwas erfasst, können Sie eine nicht erfassende Gruppe verwenden, die in boost :: regex durch Einfügen einer ?: nach der ersten Klammer erfolgt: (?:Green|Red). Jetzt hat die Regex das Gruppierungsverhalten von Klammern, aber es gibt kein Capturen.

Das zweite Problem ist die (.*)

Dies scheint nicht wie viel, aber sie paßt zu viel, einschließlich Muster wie aufeinander folgende Spannweiten. Dies wird das Ende einer Spanne und den Beginn der nächsten Spanne bis zur letzten Spanne auf der Seite verbrauchen. Sie müssen dies nicht gierig machen. In boost :: regex tun Sie das, indem Sie * mit ? folgen. ändere es so, dass es wie (.*?) aussieht (und mit den anderen * s ähnlich.

Die Sache ist, XML und HTML sind sehr schwer zu bekommen mehr als trivial einfache Regexe, um richtig zu arbeiten. Sie sollten wirklich eine Bibliothek verwenden Damit ist gemeint, für mit diesem Format arbeiten. Es gibt viele options. Auf diese Weise können Sie sicher sein, dass Sie HTML korrekt sind Handling, egal wie verzerrt die Eingabe sein könnte.

+0

Das verwirrt mich wirklich. Ihr Vorschlag (Grün | Rot) erfasst entweder Grün oder Rot. Damit bekomme ich jetzt zwei Caputes: Green und 0.12. Ich möchte nur 0,12 zwischen den Spannen bekommen. – nhaa123

+0

Einfach zu beheben, siehe editierter Beitrag. – SingleNegationElimination

1
[Green|Red] 

falsch ist, weil [] gibt a character class in den meisten Regex-Syntaxen.Klassenklassen sind grundsätzlich Gruppen von Zeichen, die alle zusammenpassen können.Zum Beispiel wird [abc] "a", "b" oder "c" entsprechen.

Wie für Ihre anderen Probleme gibt es ein paar Möglichkeiten, wie TokenMacGuy Erwähnungen; (. *) könnte zu viel übereinstimmen. Um sicher zu sein, müsste ich sehen, was genau Ihre Regex zusammenbringt.

Schließlich sollten Sie keine regulären Ausdrücke verwenden, um HTML zu analysieren. Es kommt zu einem Pint, wo es einfach nicht funktioniert, außer unter den kontrollierten Bedingungen und mit den komplizierten Ausdrücken. Es wäre besser, verschiedene html/xml-Parser zu betrachten.

Edit: This ist eine großartige Erklärung dafür, warum es eine schlechte Idee ist.