Home > Net >  Parsing text file with symbol
Parsing text file with symbol

Time:01-27

I cant parse all text from .txt file But when I run my code, I don't get what I wanted :(

My code:

int main()
{
  /* inside "logMsg.txt"
  1/ [111]{1}(text line from 111);
  2/ [222]{2}(text line from 222);
  3/ [333]{3}(text line from 333);
  */

  ifstream textfile("logMsg.txt");

  string log_line;
  string log_time;
  string log_type;
  string log_comment;

  // Get line number
  getline(textfile, log_line, '/');

  // Get Time by unix
  getline(textfile, log_time, '[');
  getline(textfile, log_time, ']');

  // Get type of the function
  getline(textfile, log_type, '{');
  getline(textfile, log_type, '}');

  // Get comment from data_
  getline(textfile, log_comment, '(');
  getline(textfile, log_comment, ')');

  cout << "Line Of the log: " << log_line << "\n";
  cout << "Type of the log: " << log_type << "\n";
  cout << "Time of the log: " << log_time << "\n";
  cout << "Comment of the log :" << log_comment << "\n";
}

Console:

Line Of the log: 1
Type of the log: 1
Time of the log: 111
Comment of the log :text line from 111

I wanted the parser to read all the lines, but the result is completely different

I don't understand what I'm doing wrong, I trying to get the following result:

Line Of the log: 1, 2, 3,
Type of the log: 1, 2, 3,
Time of the log: 111, 222, 333,
Comment of the log: text line from 111, text line from 222, text line from 333,

plz help :(

CodePudding user response:

I would recommend using regular expressions for this:

  • The example below just parses each line using a given pattern. You may need to modify it, for instance, allowing whitespaces around certain fields.

[Demo]

#include <fmt/core.h>
#include <iostream>  // cout
#include <regex>
#include <sstream>  // istringstream
#include <string>  // getline

int main() {
    const std::string input{"1/ [111]{1}(text line from 111);\n2/ [222]{2}(text line from 222);\n3/ [333]{3}(text line from 333);"};
    std::istringstream iss{input};

    std::string line{};
    while (std::getline(iss, line))
    {
        const std::regex pattern{R"(([\d ])/\s*\[(\d )\]\{(\d )\}\(([^)] )\);)"};
        std::smatch matches{};
        if (std::regex_match(line, matches, pattern))
        {
            std::cout << fmt::format ("Line: {}, type: {}, time: {}, comment: {}\n",
                matches[1].str(), matches[2].str(), matches[3].str(), matches[4].str());
        }
    }
}

// Outputs:
//
//   Line: 1, type: 111, time: 1, comment: text line from 111
//   Line: 2, type: 222, time: 2, comment: text line from 222
//   Line: 3, type: 333, time: 3, comment: text line from 333
  • Should you want a different output (e.g. as it seems you suggest in your question, print all the line numbers, then all the times, and so on), you may want to use std::vectors for keeping that information, and printing it at the end.

[Demo]

#include <algorithm>  // copy
#include <iostream>  // cout
#include <iterator>  // ostream_iterator
#include <regex>
#include <sstream>  // istringstream
#include <string>  // getline

int main() {
    const std::string input{"1/ [111]{1}(text line from 111);\n2/ [222]{2}(text line from 222);\n3/ [333]{3}(text line from 333);"};
    std::istringstream iss{input};

    std::vector<std::string> numbers{};
    std::vector<std::string> types{};
    std::vector<std::string> times{};
    std::vector<std::string> comments{};
    std::string line{};
    while (std::getline(iss, line))
    {
        const std::regex pattern{R"(([\d ])/\s*\[(\d )\]\{(\d )\}\(([^)] )\);)"};
        std::smatch matches{};
        if (std::regex_match(line, matches, pattern))
        {
            numbers.push_back(matches[1]);
            types.push_back(matches[2]);
            times.push_back(matches[3]);
            comments.push_back(matches[4]);
        }
    }
    std::cout << "Line of the log: ";
    std::copy(numbers.cbegin(), numbers.cend(), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << "\n";
    std::cout << "Type of the log: ";
    std::copy(types.cbegin(), types.cend(), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << "\n";
    std::cout << "Time of the log: ";
    std::copy(times.cbegin(), times.cend(), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << "\n";
    std::cout << "Comment of the log: ";
    std::copy(comments.cbegin(), comments.cend(), std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << "\n";
}

// Outputs:
//
//   Line of the log: 1, 2, 3, 
//   Type of the log: 111, 222, 333, 
//   Time of the log: 1, 2, 3, 
//   Comment of the log: text line from 111, text line from 222, text line from 333, 
  • Although you'd better use a single std::vector of structs, with proper types for the numbers, types and times. In this case, you would need to convert the strings from matches to the struct's ints (you could do that with std::stoi).

[Demo]

struct LineInfo
{
    int number{};
    int type{};
    int time{};
    std::string comment{};
};
std::vector<LineInfo> line_infos{};
  •  Tags:  
  • Related