Parsing file in C++ and writing it into HTML in table

淺唱寂寞╮ 提交于 2021-01-29 07:59:17

问题


I need to convert existing log file into HTML report. I'm working on Windows platform. Below is the example of the log messages from the log file.

Example of log file

MyProcess1 16-06-14 8:32:50 8667 [Info] This is an information message

MyProcess2 16-06-14 8:32:57 9876 [Warn] This warning message

Please Note the format of the log file

MyProcess1 "space" 16-06-14 "space" 8:32:50 "space" 8667 "space" [Info] "space" This "space" is "space" an "space" information "space" message

Expected HTML report

enter image description here

At the moment I could thought of creating txt file with Header, footer tags & table tags. And Adding tags in the begining and the end of lines. But am struggling to those tags in the lines for different targerted columns. We cannot replace all spaces with tags because there spaces in the Message description. Can you please suggest any new approach or any suggestion on below tried code.

    #include "stdafx.h"    
    #include <string>
    #include <fstream>
    #include <iostream>

    int main()
    {
        std::ifstream inputFile("C:\\Test\\log.txt");
        std::ofstream outputFile("C:\\Test\\Report.txt");

        std::string line;
        while (std::getline(inputFile, line))
            outputFile << "<tr><td> " << line << " </tr></td>"<< std::endl;

        return 0;
    }

回答1:


Read the data into some sort of struct/class that reflects the logical structure of the data. As one possibility (though certainly not the only one) use an overloaded operator<< to write the data out with the correct markup applied. General approach would look something like this:

#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <iterator>

std::string input = "MyProcess1 16-06-14 8:32:50 8667 [Info] This is an information message\nMyProcess2 16-06-14 8:32:57 9876 [Warn] This warning message";

struct cell {
    cell(std::string const &data) :content(data) {}
    std::string const &content;

    friend std::ostream &operator<<(std::ostream &os, cell const &c) {
        return os << "<td>" << c.content << "</td>";
    }
};

struct row {
    friend std::istream &operator>>(std::istream &is, row &r) {
        is >> r.process >> r.date >> r.time >> r.process_id >> r.level;
        return std::getline(is, r.msg);
    }

    friend std::ostream &operator<<(std::ostream &os, row const &r) {
        return os << "<tr>" << cell(r.process) << cell(r.date) << cell(r.time) << cell(r.process_id) << cell(r.level) << cell(r.msg) << "</tr>";
    }

private:
    std::string process;
    std::string date;
    std::string time;
    std::string process_id;
    std::string level;
    std::string msg;
};

struct table {
    table(std::vector<row> const &r) :t(r) { }
    std::vector<row> const &t;

    friend std::ostream &operator<<(std::ostream &os, table const &t) {
        os << "<table>";
        std::copy(t.t.begin(), t.t.end(), std::ostream_iterator<row>(os));
        return os << "</table>";
    }
};

int main(){
    std::istringstream rows(input);
    std::vector<row> data{
        std::istream_iterator<row>(rows),
        std::istream_iterator<row>()
    };

    std::cout << table(data);
}



回答2:


This is an excellent example of where the std::regex class that is part of the C++11 standard can be useful in simplifying the design. The following example takes your two sample input strings and matches them against a regex. The regex uses capturing parenthesis to capture those portions of the input data that are relevant. We push that captured data into a structure which we later send to out HTML output routine.

The HTML output routine just iterates over the data structure that we built using the regex, and wraps the data in the correct HTML tags.

#include <iostream>
#include <regex>
#include <string>
#include <vector>

void print_table(
  std::vector<std::string>,
  std::vector<std::vector<std::string>>
);

int main () {

  std::vector<std::string> tests {
    "MyProcess1 16-06-14 8:32:50 8667 [Info] This is an information message",
    "MyProcess2 16-06-14 8:32:57 9876 [Warn] This warning message"
  };
  std::vector<std::string> headings {
    "Process Name", "Date",            "Time",
    "Thread ID",    "Type of Message", "Message Description"
  };
  //                   PN     D      T      TID      MT          MD
  std::regex rx { R"(^(\S+)\s(\S+)\s(\S+)\s(\S+)\s\[([^\]]+)\]\s(.+)$)" };
  std::vector<std::vector<std::string>> tabular_data;

  for( auto target : tests ) {
    std::smatch m;
    if( std::regex_search( target, m, rx ) ) {
      tabular_data.push_back(
        std::vector<std::string>( m.begin()+1, m.end() )
      );
    }
  }

  print_table( headings, tabular_data );
  return 0;
}

void print_table(
  std::vector<std::string> header,
  std::vector<std::vector<std::string>> data
) {

  std::cout << "<table>\n"
            << "  <tr>\n";

  for( auto head : header ) {
    std::cout << "    <th>" << head << "</th>\n";
  }
  std::cout << "  </tr>\n";

  for( auto row : data ) {
    std::cout << "  <tr>\n";
    for( auto col : row ) {
      std::cout << "    <td>" << col << "</td>\n";
    }
    std::cout << "  </tr>\n";
  }

  std::cout << "</table>\n";
}

Here is the output that produces:

<table>
  <tr>
    <th>Process Name</th>
    <th>Date</th>
    <th>Time</th>
    <th>Thread ID</th>
    <th>Type of Message</th>
    <th>Message Description</th>
  </tr>
  <tr>
    <td>MyProcess1</td>
    <td>16-06-14</td>
    <td>8:32:50</td>
    <td>8667</td>
    <td>Info</td>
    <td>This is an information message</td>
  </tr>
  <tr>
    <td>MyProcess2</td>
    <td>16-06-14</td>
    <td>8:32:57</td>
    <td>9876</td>
    <td>Warn</td>
    <td>This warning message</td>
  </tr>
</table>

... a well-formed HTML table. Apply your CSS to beautify it to taste.



来源:https://stackoverflow.com/questions/24255935/parsing-file-in-c-and-writing-it-into-html-in-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!