moeglichst elegant logfile parsen



  • Hallo,
    ich habe vor ein ASCII tcpdump logfile einzulesen, wobei eine Zeile folgendes Format hat:
    18:12:27.808667 14744803536us tsft short preamble 54.0 Mb/s 2437 MHz (0x0480) -25dB signal -96dB noise antenna 1 71dB signal 44us 00:14:6c:0d:60:c2 (oui Unknown) > 00:18:4d:8a:b4:f6 (oui Unknown) Null Information, send seq 0, rcv seq 0, Flags [Command], length 1480

    Zeilenweise einlesen tue ich das file mit:

    std::string line;
    std::ifstream infile(filename, std::ios_base::in);
    while (getline(infile, line, '\n')) {
       // Zeile bearbeiten
    }
    

    Nun habe ich bisher immer jede Zeile in std::strings tokens geteilt (Leerzeichen) und diese fuer weitere Verarbeitung in einen std::vectorstd::string gepusht. Allerdings brauche ich von der Zeile oben nur 54.0 00:14:6c:0d:60:c2 00:18:4d:8a:b4:f6 1480

    Mein erster Gedanke war irgendwie scanf nachzubasteln

    std::string input = "foo bar 10 20 hello 30"
    int a,b,c;
    std::string garbage;
    stringstream foo;
    foo << input;
    input >> garbage >> garbage >> a >> b >> garbage >> c;
    

    finde das aber nicht sehr effizient.

    Also meine Frage ist, wie ich aus der Zeile am elegantesten die Werte extrahiere die mich interessieren?



  • alpha21 schrieb:

    Hallo,
    ich habe vor ein ASCII tcpdump logfile einzulesen, wobei eine Zeile folgendes Format hat:
    18:12:27.808667 14744803536us tsft short preamble 54.0 Mb/s 2437 MHz (0x0480) -25dB signal -96dB noise antenna 1 71dB signal 44us 00:14:6c:0d:60:c2 (oui Unknown) > 00:18:4d:8a:b4:f6 (oui Unknown) Null Information, send seq 0, rcv seq 0, Flags [Command], length 1480

    Wenn die zeile gleich bleibt, leg ne while drüber und schmeiss die unnötigen teile wieder aus dem vector

    string tmpstr = "aa bb cc";
    	istringstream iss(tmpstr);
    
    	vector<string> parts;
    	copy(istream_iterator<string>(iss),istream_iterator<string>(),back_inserter<vector<string>>(parts));
    


  • eine idee waere vielleicht:

    class skip_strings
    {
       public:
          skip_strings(int val = 1) : value(val) { }
    
          std::istream& operator()(std::istream &in)
          {
             if(value == 0)
                return in;
    
             std::streambuf *buf = in.rdbuf();   
             char c = buf->sgetc(); 
    
             do
             {  
                while(std::isspace(c)) c = buf->snextc();
                while(c != EOF && !std::isspace(c)) c = buf->snextc();  
             } while(--value);
    
             return in;
          }
    
       private:
          int value;
    };
    
    std::string input = "foo bar 10 20 hello 30"
    int a,b,c;
    std::string garbage;
    stringstream foo;
    foo << input;
    input >> skip_strings(2) >> a >> b >> skip_strings(1) >> c;
    

    ungetestet und aus dem kopf

    Meep Meep



  • schöne idee, wie ich finde.
    nur die zeile

    skip_strings(int val = 1) : value(val) { }
    

    find ich doof.

    1. explicit vergessen?!
    2. wieso default-parameter? (wer soll später bei stream >> skip_strings() >> ... wissen, was dort passiert?)
    3. wieso signed?

    ich würde auch den namen in skip_dates oder so was in der richtung ändern.
    skip_strings klingt so, als ob er aufhören würde, wenn er an einer zahl angelangt ist.

    bb



  • (1) ja
    (2) keine ahnung wasich dabei gedacht habe
    (3) sollte unsigned sein sonst muesste es 'if(value <= 0)' heissen

    Meep Meep



  • alpha21 schrieb:

    std::string input = "foo bar 10 20 hello 30"
    int a,b,c;
    std::string garbage;
    stringstream foo;
    foo << input;
    input >> garbage >> garbage >> a >> b >> garbage >> c;
    

    finde das aber nicht sehr effizient.

    Vollkommen ausreichend und kommt ohne zusätzliches gefrickel aus.


Log in to reply