Boost - RegExs, kein dynamischer Replacement-String



  • In Perl habe ich diese Funktion:

    sub parse_content()
    {
            my $content     =$_[0];
            my $hash_ref    =$_[1];
            $$content=~s#\$\$(.+?)\$\$#$hash_ref->{$1}#sg;
    }
    

    Die Funktion geht an sich jedes $$blabla$$ durch und erstetzt es durch den Wert, welcher durch die Nutzung des Schlüssels $1 in der Hash-Ref rauskommt - zum automatischen Befüllen von Formularen eben.

    Das gleiche wollte ich für C++ in Verbindung mit Boost machen (was Boost angeht, bin ich noch Neuling, aber ich habe es geschafft, auf Linux zu installieren, ohne dass die Kiste brennt). Problem ist aber, dass regex_replace irgendwie davon ausgeht, dass ich einen genauen Plan davon habe, was ich in $$blabla$$ setzen will. Oben sag ich ja: "Och, such mal nach allem und verwende das als Key", mit Boost kann ich aber nur angeben: "Och, such mal nach allem und verwende immer DIESEN Key":

    void parse_content(std::string& s,boost::unordered_map&m)
    {
            boost::regex pat="\\$\\$(.+?)\\$\\$";
            boost::regex_replace(s,pat,m["\\1"]);//Hier das Problem, in allen Beispielen kann ich nur die Platzhalter oder einen festen String angeben, aber niemals MIT dem Platzhalter auf einen Wert zugreifem.
    }
    

    Ich könnte mir ein Konstrukt überlegen, in dem ich den String erst nach allen $$blabla$$ durchsuche und mir dann anhand der Reihenfolge merke, welche Strings wodurch zu ersetzen sind, denn an die unsortierten Werte scheine ich so oder so nicht ohne Vorwissen dranzukommen - oder?
    Würde jetzt ungern loslegen und dann später gesagt bekommen, dass es einen ganz einfachen Kniff gibt, den ich nur mit stundenlangem Google-Suchen nicht finden konnte ...



  • Der aus dem Westen .. schrieb:

    (was Boost angeht, bin ich noch Neuling, aber ich habe es geschafft, auf Linux zu installieren, ohne dass die Kiste brennt).

    Die neueren boost Versionen haben einen verzögerten Selbstzerstörungsmechanismus, dein Prozessor wird übertaktet und durchbrennen, wenn du es am wenigsten erwartest.

    Ich hab boost::regexp noch nie benutzt, aber das geht bestimmt. Musst halt nach umfangreicheren Beispielen suchen.



  • boost::regex_replace frisst einen Format-Funktor, in dem man einen match auf alles mögliche adaptern kann. Mal ganz simpel gestrickt:

    #include <boost/regex.hpp>
    #include <boost/ref.hpp>
    #include <boost/unordered_map.hpp>
    
    #include <iostream>
    #include <string>
    
    typedef boost::unordered_map<std::string, std::string> token_map;
    
    class token_adapter {
    public:
      token_adapter(token_map const &map) : map_(map) { }
    
      std::string operator()(boost::smatch const &what) const {
        token_map::const_iterator i = map_.get().find(what.str(1));
    
        if(i == map_.get().end()) {
          return "(null)";
        }
    
        return i->second;
      }
    
    private:
      boost::reference_wrapper<token_map const> map_;
    };
    
    std::string process_content(std::string const &s, token_map const &m)
    {
      boost::regex pat("\\$\\$([^\\$]*)\\$\\$");
      return boost::regex_replace(s, pat, token_adapter(m));
    }
    
    int main() {
      token_map m;
      std::string s = "lala $$foo$$ xxx foo $$quux$$ $$bla$$ yz";
    
      m["foo"] = "bar";
      m["quux"] = "xyzzy";
    
      std::cout << process_content(s, m) << '\n';
    }
    

    Das sieht mit Lambdas natürlich hübscher aus, aber ich weiß nicht, ob du dich schon auf C++11 stützen kannst.


Anmelden zum Antworten