<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Die großen Dinge parsen]]></title><description><![CDATA[<p>Hallo Community!</p>
<p>Kennt sich hier wer mit Parsen aus? Ich wollte mal im Allgemeinen Fragen, wie man &quot;größere&quot; Dinge parst. Ich habe bisher immer nur std::string und die iostreams im imperativen Stil verwendet um Dinge zu parsen. Aber was, wenn es mal was größeres ist? Sagen wir zum Beispiel einen IMAP-Mail-Parser oder gar ne ganze Sprache! Da ist mir aufgefallen, dass das eine ziemlich heikele Sache ist, wenn man imperativ und mit Streams arbeitet. Gibt es hier vielleicht nennenswerte Idiome, oder gar ganze Parsing-Libraries, die einem das Parsen vereinfachen können?</p>
<p>Ich habe auch ein Beispiel. Teil einer Mail:</p>
<pre><code>Received: from (domain [IP])
        by mx.google.com with ESMTP id u6si2825139wia.7.2015.09.12.06.35.39;
        Sat, 12 Sep 2015 06:35:39 -0700 (PDT)
</code></pre>
<p>Dazu habe ich eine normale Struktur gebaut, die ganz simpel wie folgt aussieht:</p>
<pre><code class="language-cpp">struct value_pair{
    std::string name, value;

    void parse(std::istream&amp; stream){
        ...
    }
};
</code></pre>
<p>Nur, wie kann ein Parser erkennen, ob die nächste Zeile noch zum gleichen value_pair gehört oder nicht? Nicht jede Zeile endet mit ';' oder ',' wie man oben an meinem Beispiel erkennen kann.</p>
<p>Die einzige Möglichkeit, die mir einfällt ist es, eine Helper-Funktion zu bauen, die einem die nächste Zeile eines Streams zurückgibt, ohne jedoch die Position des Streams selbst zu verändern. Dann schau ich nach, ob in der besagten nächsten Zeile ein ':' vorkommt, wenn nicht, gehört die nächste Zeile zum selben value_pair, andernfalls ist es ein anderes value_pair. Und nun stellt euch vor, die nächste Zeile gehört tatsächlich noch zum selben value_pair, nur dass in diesem Wert tatsächlich ein Doppelpunkt vorkommt. Und schon macht meine Methode keinen Sinn mehr.</p>
<p>Kann mir jemand bei dem Parsen der Mails auf die Sprünge helfen?<br />
Kennt wer irgendwelche guten Parsing-Techniken (Idiome, Libraries)?</p>
<p>Würde mich auf Antworten freuen.</p>
<p>Liebe Grüße,<br />
Farmer123</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/338600/die-großen-dinge-parsen</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 10:16:23 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/338600.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 26 Jun 2016 19:15:48 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Die großen Dinge parsen on Sun, 26 Jun 2016 19:15:48 GMT]]></title><description><![CDATA[<p>Hallo Community!</p>
<p>Kennt sich hier wer mit Parsen aus? Ich wollte mal im Allgemeinen Fragen, wie man &quot;größere&quot; Dinge parst. Ich habe bisher immer nur std::string und die iostreams im imperativen Stil verwendet um Dinge zu parsen. Aber was, wenn es mal was größeres ist? Sagen wir zum Beispiel einen IMAP-Mail-Parser oder gar ne ganze Sprache! Da ist mir aufgefallen, dass das eine ziemlich heikele Sache ist, wenn man imperativ und mit Streams arbeitet. Gibt es hier vielleicht nennenswerte Idiome, oder gar ganze Parsing-Libraries, die einem das Parsen vereinfachen können?</p>
<p>Ich habe auch ein Beispiel. Teil einer Mail:</p>
<pre><code>Received: from (domain [IP])
        by mx.google.com with ESMTP id u6si2825139wia.7.2015.09.12.06.35.39;
        Sat, 12 Sep 2015 06:35:39 -0700 (PDT)
</code></pre>
<p>Dazu habe ich eine normale Struktur gebaut, die ganz simpel wie folgt aussieht:</p>
<pre><code class="language-cpp">struct value_pair{
    std::string name, value;

    void parse(std::istream&amp; stream){
        ...
    }
};
</code></pre>
<p>Nur, wie kann ein Parser erkennen, ob die nächste Zeile noch zum gleichen value_pair gehört oder nicht? Nicht jede Zeile endet mit ';' oder ',' wie man oben an meinem Beispiel erkennen kann.</p>
<p>Die einzige Möglichkeit, die mir einfällt ist es, eine Helper-Funktion zu bauen, die einem die nächste Zeile eines Streams zurückgibt, ohne jedoch die Position des Streams selbst zu verändern. Dann schau ich nach, ob in der besagten nächsten Zeile ein ':' vorkommt, wenn nicht, gehört die nächste Zeile zum selben value_pair, andernfalls ist es ein anderes value_pair. Und nun stellt euch vor, die nächste Zeile gehört tatsächlich noch zum selben value_pair, nur dass in diesem Wert tatsächlich ein Doppelpunkt vorkommt. Und schon macht meine Methode keinen Sinn mehr.</p>
<p>Kann mir jemand bei dem Parsen der Mails auf die Sprünge helfen?<br />
Kennt wer irgendwelche guten Parsing-Techniken (Idiome, Libraries)?</p>
<p>Würde mich auf Antworten freuen.</p>
<p>Liebe Grüße,<br />
Farmer123</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500232</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500232</guid><dc:creator><![CDATA[Farmer123]]></dc:creator><pubDate>Sun, 26 Jun 2016 19:15:48 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Sun, 26 Jun 2016 19:35:53 GMT]]></title><description><![CDATA[<p>Besorg dir z.B. folgendes Buch (auch als pdf im www findbar).</p>
<p>Parr - Language Implementation Patterns</p>
<p>Parsen ist durchaus ein komplexes Thema,<br />
aber bereits gut erforscht. D.h du wirst zu deinem Problem bereits Pattern finden, welche dieses lösen, ein bisschen Theorie brauchst du aber trotzdem. In obigem Buch findest du beides (Theorie+Praxis).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500233</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500233</guid><dc:creator><![CDATA[sgjlojgdsfvnkufd]]></dc:creator><pubDate>Sun, 26 Jun 2016 19:35:53 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 07:08:45 GMT]]></title><description><![CDATA[<p>Schau dir mal <a href="http://boost-spirit.com/home/" rel="nofollow">Boost Spirit</a> an.</p>
<p>Für das Parsen von IMAP schau einfach in die Spec: <a href="https://tools.ietf.org/html/rfc3501" rel="nofollow">INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1</a> (unter Kapitel 9 ist dann die Beschreibung als <a href="https://de.wikipedia.org/wiki/Angereicherte_Backus-Naur-Form" rel="nofollow">ABNF</a>, welche man dann (fast) 1:1 mittels Boost.Spirit umsetzen kann).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500245</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500245</guid><dc:creator><![CDATA[Th69]]></dc:creator><pubDate>Mon, 27 Jun 2016 07:08:45 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 12:49:00 GMT]]></title><description><![CDATA[<p>Danke, ich werde mich etwas näher mit all dem beschäftigen.<br />
Boost.Spirit sieht interessant aus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500264</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500264</guid><dc:creator><![CDATA[Farmer123]]></dc:creator><pubDate>Mon, 27 Jun 2016 12:49:00 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 14:37:39 GMT]]></title><description><![CDATA[<p>Ich hab mich etwas in Boost.Spirit reingelesen und habe es geschafft einen kleinen Mathe-Parser zu machen. Nun verstehe ich noch nicht, wie man die Werte vernünftig ansprechen kann. Folgender Code:</p>
<pre><code class="language-cpp">#include &lt;boost/spirit/include/qi.hpp&gt;
#include &lt;iostream&gt;

using namespace boost::spirit::qi;

void add(double x){
    std::cout &lt;&lt; x &lt;&lt; '\n';
}

int main(){
    rule&lt;std::string::iterator, ascii::space_type&gt; add_expr, sub_expr, mult_expr, div_expr, math_expr, term, fact, group;

    term = double_;
    fact = term | group;
    group = char_('(') &gt;&gt; math_expr &gt;&gt; char_(')');

    add_expr = +(char_('+') &gt;&gt; fact)[add];
    sub_expr = +(char_('-') &gt;&gt; fact);
    mult_expr = +(char_('*') &gt;&gt; fact);
    div_expr = +(char_('/') &gt;&gt; fact);
    math_expr = fact &gt;&gt; *(add_expr | sub_expr | mult_expr | div_expr);

    std::string str = &quot;1+1+(1+1)&quot;;
    std::string::iterator it = str.begin();

    phrase_parse(it, str.end(), math_expr, ascii::space);
    std::cout &lt;&lt; &amp;*it &lt;&lt; '\n';
}
</code></pre>
<p>In Zeile 19 versuche ich über eine Funktion an den Wert zu kommen, doch dieser lautet genau dreimal 43. Woher kommt diese 43? Und wie spreche ich die 1 an?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500277</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500277</guid><dc:creator><![CDATA[Farmer123]]></dc:creator><pubDate>Mon, 27 Jun 2016 14:37:39 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 14:55:45 GMT]]></title><description><![CDATA[<p>Ist schon ein bißchen her, seitdem ich mit Spirit gearbeitet habe, aber 43 (hex: 2B) ist der ASCII-Code für '+' <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";-)"
      alt="😉"
    /><br />
Die Zahlen (Terminalzeichen) definiserst du ja mittels</p>
<pre><code class="language-cpp">term = double_;
</code></pre>
<p>Schau mal, ob du mittels</p>
<pre><code class="language-cpp">void number(double x)
{
    std::cout &lt;&lt; x &lt;&lt; '\n';
}

term = double_[number];
</code></pre>
<p>an die Zahlen kommst.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500278</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500278</guid><dc:creator><![CDATA[Th69]]></dc:creator><pubDate>Mon, 27 Jun 2016 14:55:45 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 15:17:42 GMT]]></title><description><![CDATA[<p>Ja, damit komm ich zwar an die Zahlen, das Problem dabei ist jedoch, dass ich so nicht weiß wie ich addieren, subtrahieren, etc. soll. Ich habe mir das so vorgestellt, dass ich vorerst mal ne globale &quot;double result = 0;&quot; mache und bei den entsprechenden Parsern dann die Operation mache. Im Sinne von:</p>
<pre><code class="language-cpp">double res = 0;

void add(double x){
    res += x;
}

add_expr = +(char_('+') &gt;&gt; fact)[add];
</code></pre>
<p>Ist mein Vorhaben realisierbar?</p>
<p>Ich habe auch schon folgendes versucht:</p>
<pre><code class="language-cpp">#include &lt;boost/spirit/include/qi.hpp&gt;

using namespace boost::spirit::qi;

void add(boost::fusion::vector&lt;char, double&gt; x){
    std::cout &lt;&lt; boost::fusion::at_c&lt;1&gt;(x) &lt;&lt; '\n';
}

int main(){
    rule&lt;std::string::iterator, ascii::space_type&gt; add_expr, sub_expr, mult_expr, div_expr, math_expr, term, group;
    rule&lt;std::string::iterator, double, ascii::space_type&gt; fact = term | group;

    term = double_;
    group = char_('(') &gt;&gt; math_expr &gt;&gt; char_(')');

    add_expr = +(char_('+') &gt;&gt; fact)[add];
    sub_expr = +(char_('-') &gt;&gt; fact);
    mult_expr = +(char_('*') &gt;&gt; fact);
    div_expr = +(char_('/') &gt;&gt; fact);
    math_expr = fact &gt;&gt; *(add_expr | sub_expr | mult_expr | div_expr);

    std::string str = &quot;1+1&quot;;
    std::string::iterator it = str.begin();

    phrase_parse(it, str.end(), math_expr, ascii::space);
    std::cout &lt;&lt; &amp;*it &lt;&lt; '\n';
}
</code></pre>
<p>Das kompiliert, aber damit wird mir nur einmal 0 ausgegeben und verstehe nicht woher diese Null auf einmal herkommt.</p>
<p>Und so hätte ich es mir am schönsten vorgestellt, kompiliert nur leider nicht:</p>
<pre><code class="language-cpp">void dowork(boost::fusion::vector&lt;double, boost::fusion::vector&lt;char, double&gt;&gt; x){}
 math_expr = (fact &gt;&gt; *((char_('+')|char_('-')|char_('*')|char_('/')) &gt;&gt; fact))[dowork];
</code></pre>
<p>PS: Ja, das mit dem '+' war ein char, stimmt!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500280</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500280</guid><dc:creator><![CDATA[Farmer123]]></dc:creator><pubDate>Mon, 27 Jun 2016 15:17:42 GMT</pubDate></item><item><title><![CDATA[Reply to Die großen Dinge parsen on Mon, 27 Jun 2016 16:09:34 GMT]]></title><description><![CDATA[<p>Ich habs nun irgendwie geschafft.</p>
<pre><code class="language-cpp">#include &lt;boost/spirit/include/qi.hpp&gt;

namespace qi = boost::spirit::qi;

template&lt;typename Iterator&gt;
class math_parser : public qi::grammar&lt;Iterator, qi::ascii::space_type&gt;{
    qi::rule&lt;Iterator, qi::ascii::space_type&gt; start;
    qi::rule&lt;Iterator, double, qi::ascii::space_type&gt; term, fact, group;
    qi::rule&lt;Iterator&gt; identifier;

    void work(boost::fusion::vector&lt;double, std::vector&lt;boost::fusion::vector&lt;char, double&gt;&gt;&gt;&amp; values){
        result = boost::fusion::at_c&lt;0&gt;(values);
        auto vec = boost::fusion::at_c&lt;1&gt;(values);

        double value;
        char op;

        for(auto&amp;&amp; v : std::move(vec)){
            op = boost::fusion::at_c&lt;0&gt;(v);
            value = boost::fusion::at_c&lt;1&gt;(v);

            switch(op){
                case '+':
                    result += value;
                    break;

                case '-':
                    result -= value;
                    break;

                case '*':
                    result *= value;
                    break;

                case '/':
                    result /= value;
            }
        }
    }

public:
    double result;

    math_parser() : qi::grammar&lt;Iterator, qi::ascii::space_type&gt;(start){
        identifier = qi::alpha &gt;&gt; *(qi::alnum);

        term = qi::double_ | identifier;

        fact = term | group;

        group = qi::char_('(') &gt;&gt; start &gt;&gt; qi::char_(')');

        start = (fact &gt;&gt; *((qi::char_('+') | qi::char_('-') | qi::char_('*') | qi::char_('/')) &gt;&gt; fact))
        [std::bind(&amp;math_parser::work, this, std::placeholders::_1)];
    }
};

#include &lt;iostream&gt;

int main(){
    std::string str = &quot;(1)+2+3&quot;;
    std::string::iterator it = str.begin();
    math_parser&lt;decltype(it)&gt; parser;

    qi::phrase_parse(it, str.end(), parser, qi::ascii::space);
    std::cout &lt;&lt; parser.result &lt;&lt; '\n';
}
</code></pre>
<p>Da gibt es nur ein winziges Problem. Bei Expressions wie &quot;1+2+3&quot; klappt alles wundersam, jedoch, sobald ich die Klammern setze, werden diese Klammern mitberechnet. Was ich also suche, ist es, dem Parser &quot;group&quot; irgendwie mitzuteilen, was genau er zurückgeben soll. Wie mach ich das? Oder denke ich schon wieder in die falsche Richtung?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2500285</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2500285</guid><dc:creator><![CDATA[Farmer123]]></dc:creator><pubDate>Mon, 27 Jun 2016 16:09:34 GMT</pubDate></item></channel></rss>