2016-06-19 9 views
1

Ich arbeite daran zu lernen, Spirit Grammatiken zu schreiben, und ich versuche, eine Basis Basis 16 zu Base 64-Konverter erstellen, die eine Zeichenfolge für Hexadezimalwerte, zum Beispiel:Spirit Grammar Um eine Zeichenfolge durch die Anzahl der Zeichen aufzuteilen

parse out 6 oder weniger Zeichen (weniger, wenn die Zeichenfolge nicht ein perfektes Vielfaches von 6 ist) und generieren Sie eine Base 64 codierte Zeichenfolge aus dem Eingang. Eine Grammatik Ich dachte, würde wahrscheinlich funktionieren etwas wie folgt aus:

// 6 characters 
`(qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F")[/*action*/]) | 


// or 5 characters 
(qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F")[/*action*/]) | ...` 

etc .... den ganzen Weg hinunter zu einem Zeichen oder eine andere Regel für jede Anzahl von Zeichen definiert ist, aber ich denke, es muss sein eine bessere Möglichkeit, die Grammatik zu spezifizieren. Ich las über Spirit Repeat und dachte, ich könnte vielleicht etwas wie +(boost::spirit::repeat(1, 6)[qi::char_("0-9a-fA-F")][/*action on characters*/]) aber der Compiler wirft einen Fehler auf diesem, wegen der sematic Aktion Teil der Grammatik. Gibt es eine einfachere Möglichkeit, eine Grammatik anzugeben, die auf genau 6 oder weniger Zeichen gleichzeitig angewendet werden kann?

bearbeiten Hier ist, was ich bisher ... base16convertergrammar.hpp

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp>  

#include <string> 
#include <iostream> 

namespace grammar { 
    namespace qi = boost::spirit::qi; 

    void toBase64(const std::string& p_input, std::string& p_output) 
    { 
     if (p_input.length() < 6) 
     { 
      // pad length 
     } 

     // use back inserter and generator to append to end of p_output. 
    } 

    template <typename Iterator> 
    struct Base16Grammar : qi::grammar<Iterator, std::string()> 
    { 
     Base16Grammar() : Base16Grammar::base_type(start, "base16grammar"), 
      m_base64String() 
     { 
      // get six characters at a time and send them off to be encoded 
      // if there is less than six characters just parse what we have 
      start = +(boost::spirit::repeat(1, 6)[qi::char_("0-9a-fA-F")][boost::phoenix::bind(toBase64, qi::_1, 
       boost::phoenix::ref(m_base64String))]); 
     } 

     qi::rule<Iterator, std::string()> start; 

     std::string m_base64String; 
    }; 
} 

Und hier getan haben, ist die Verwendung ... base16converter.cpp

#include "base16convertergrammar.hpp" 

const std::string& convertHexToBase64(const std::string& p_hexString) 
{ 
    grammar::Base16Grammar<std::string::const_iterator> g; 
    bool r = boost::spirit::qi::parse(p_hexString.begin(), p_hexString.end(), g); 
} 


int main(int argc, char** argv) 
{ 
    std::string test("49276d206b696c6c"); 
    convertHexToBase64(test); 
} 
+1

Ich weiß nicht, ob es ein Fehler ist, während transkribieren, aber in Ihrem Beispiel der Semantische Aktionen werden nur an den letzten Ihrer Zeichen angehängt, während Sie den Rest ignorieren. Die von Ihnen vorgeschlagene Alternative sollte funktionieren und ein Attribut "vector " haben. Es wäre einfacher (und besser für Sie), wenn Sie ein (fast) vollständiges Beispiel angeben würden. – llonesmiz

+0

Ich habe hinzugefügt, was ich bisher habe. – joshu

Antwort

2

Erste von allen, repeat()[] legt einen Vektor, also vector<char>, keine Zeichenfolge.

void toBase64(const std::vector<char>& p_input, std::string& p_output) 

Zweitens, bitte tun Sie nicht alle diese Arbeit. Sie sagen uns nicht, was die Eingabe bedeutet, aber solange Sie sie in Sechsen gruppieren wollen, nehme ich an, dass Sie sie als/etwas/interpretieren wollen. Sie könnten z.B. Verwenden Sie die int_parser:

Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp>  

#include <string> 
#include <iostream> 

namespace grammar { 
    namespace qi = boost::spirit::qi; 
    namespace px = boost::phoenix; 

    template <typename Iterator> 
    struct Base16Grammar : qi::grammar<Iterator, std::string()> 
    { 
     Base16Grammar() : Base16Grammar::base_type(start, "base16grammar") 
     { 
      start = +qi::int_parser<uint64_t, 16, 1, 6>() [ qi::_val += to_string(qi::_1) + "; " ]; 
     } 

     private: 
     struct to_string_f { template <typename T> std::string operator()(T const& v) const { return std::to_string(v); } }; 
     px::function<to_string_f> to_string; 

     qi::rule<Iterator, std::string()> start; 
    }; 
} 

std::string convertHexToBase64(const std::string& p_hexString) 
{ 
    grammar::Base16Grammar<std::string::const_iterator> g; 
    std::string result; 
    bool r = boost::spirit::qi::parse(p_hexString.begin(), p_hexString.end(), g, result); 
    assert(r); 
    return result; 
} 

int main() 
{ 
    for (std::string test : {"49276d206b696c6c"}) 
     std::cout << test << " -> " << convertHexToBase64(test) << "\n"; 
} 

Drucke

49276d206b696c6c -> 4794221; 2124649; 27756; 
1

auf einem Bein Ausgehen, wollen Sie nur hex-codierte binäre in Base64 zu transcodieren.

Da Sie bereits Boost:

Live On Coliru

#include <boost/archive/iterators/base64_from_binary.hpp> 
#include <boost/archive/iterators/insert_linebreaks.hpp> 
#include <boost/archive/iterators/transform_width.hpp> 

// for hex decoding 
#include <boost/iterator/function_input_iterator.hpp> 

#include <string> 
#include <iostream> 
#include <functional> 

std::string convertHexToBase64(const std::string &hex) { 
    struct get_byte_f { 
     using result_type = uint8_t; 

     std::string::const_iterator hex_it; 

     result_type operator()() { 
      auto nibble = [](uint8_t ch) { 
       if (!std::isxdigit(ch)) throw std::runtime_error("invalid hex input"); 
       return std::isdigit(ch) ? ch - '0' : std::tolower(ch) - 'a' + 10; 
      }; 

      auto hi = nibble(*hex_it++); 
      auto lo = nibble(*hex_it++); 
      return hi << 4 | lo; 
     } 
    } get_byte{ hex.begin() }; 

    using namespace boost::archive::iterators; 

    using It = boost::iterators::function_input_iterator<get_byte_f, size_t>; 

    typedef insert_linebreaks< // insert line breaks every 72 characters 
     base64_from_binary<  // convert binary values to base64 characters 
      transform_width<  // retrieve 6 bit integers from a sequence of 8 bit bytes 
      It, 6, 8> >, 
     72> B64;     // compose all the above operations in to a new iterator 

    return { B64(It{get_byte, 0}), B64(It{get_byte, hex.size()/2}) }; 
} 

int main() { 
    for (std::string test : { 
      "49276d206b696c6c", 
      "736f6d65206c656e67746879207465787420746f2073686f77207768617420776f756c642068617070656e206174206c696e6520777261700a" 
     }) 
    { 
     std::cout << " === hex: " << test << "\n" << convertHexToBase64(test) << "\n"; 
    } 
} 

Drucke

=== hex: 49276d206b696c6c 
SSdtIGtpbGw 
=== hex: 736f6d65206c656e67746879207465787420746f2073686f77207768617420776f756c642068617070656e206174206c696e6520777261700a 
c29tZSBsZW5ndGh5IHRleHQgdG8gc2hvdyB3aGF0IHdvdWxkIGhhcHBlbiBhdCBsaW5lIHdy 
YXAK 
+0

Das mache ich. Ich habe diese Herausforderung tatsächlich begonnen https: // Kryptopale.com/sets/1/challenges/1 heute und trotzdem dachte ich, dass es einfach ist, eine Base 64 zu Base 16 Encoder zu machen, also habe ich beschlossen, zwei Fliegen mit einer Klappe zu schlagen und auch Spirit-Sachen zu lernen. – joshu

+0

danke für deine beiden antworten sie sind beide sehr hilfreich! – joshu