问题
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
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