解析带符号的文本文件
Parsing text file with symbol
我无法解析 .txt 文件中的所有文本
但是当我 运行 我的代码时,我没有得到我想要的:(
我的代码:
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";
}
控制台:
Line Of the log: 1
Type of the log: 1
Time of the log: 111
Comment of the log :text line from 111
我希望解析器读取所有行,但结果完全不同
我不明白我做错了什么,我试图得到以下结果:
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,
请帮忙:(
我建议为此使用正则表达式:
- 下面的示例只是使用给定的模式解析每一行。您可能需要对其进行修改,例如,允许在某些字段周围使用空格。
#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
- 如果您想要不同的输出(例如,您在问题中似乎建议打印所有行号,然后一直打印,依此类推),您可能需要使用
std::vectors
来保持该信息,并在最后打印出来。
#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,
- 尽管您最好使用
struct
中的单个 std::vector
,并为数字、类型和时间设置适当的类型。在这种情况下,您需要将字符串从 matches
转换为 struct
的 int
(您可以使用 std::stoi
)。
struct LineInfo
{
int number{};
int type{};
int time{};
std::string comment{};
};
std::vector<LineInfo> line_infos{};
阅读您的源代码,我假设您正在学习 C++ iostream 功能。正则表达式之类的东西一开始可能还是太复杂了。因此,让我们尝试使用正常的 iostream 功能生存。
基本上你应该知道有两种主要的输入类型:
- 格式化输入
- 未格式化的输入
要了解概览,请阅读有关 here 的 CPP 参考资料。
您已经了解格式化 IO,因为您一直在使用 std::cout << "Hello" << '\n';
或 std::cin >> word >> count
等语句。格式化输入函数从流中读取字符,解释它们(格式化)并将它们转换为目标类型。例如,如果您输入 int number; std::cin >> number;
,然后按 1、2、3 键,软件将读取字符“1”、“2”和“3”,然后将其转换为整数。
在幕后还有更多内容,但现在这个解释还不错。请注意 IO-operators,就像提取运算符 >>
一样,总是 return 它们被调用的流。这允许链接此类语句。 std::cin >> word >> count
的示例。首先 std::cin >> word
被执行。直到白色 space 之前的所有字符将被读取,然后转换为字符串并存储在 word
中。 >>
操作将 return 调用它的流,在我们的例子中:std::cin
。所以,读完这个词后,我们现在剩下语句 std::cin >> count
了。然后将读取计数。分隔白色 space 将被忽略。这就是它基本起作用的原因和方式。
一个更重要的属性是>>
操作跳过任何潜在的白色space(包括换行符'\n')然后开始转换。如果读取的字符不能再转换为目标变量,它将停止读取和使用输入流中的字符。这又包括白色 space.
如果流中有 1/ [111]{1}(text line from 111);
并写入 stream >> number;
,那么它将读取字符 1 并开始转换为整数。然后它会看到以下“/”字符。它停止读取并将“1”转换为数字 1,但是,它不会从流中提取“/”。它仍然存在,可以而且必须阅读。因此,如果我们定义一个 char
变量 c1
并写入 stream >> number >> c1
那么首先数字将被读取为 number
并且 '/' 将被读取为 c1
.空格将被忽略。
通过使用这种机制,您可以像这样读取字符串的第一部分:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6;
std::string comment;
test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6;
return 0;
}
(cx 变量只是虚拟变量)
变量将是:
这符合预期。空间不会以任何方式打扰这里。
现在是下一部分,注释,所以字符串中的 text line from 111
。如您所见,它包含 spaces。并且由于格式化输入函数在白色 space 处停止转换,我们不能使用像 >>
这样的格式化输入函数将完整的文本读入一个字符串变量。
现在我们需要使用像std::getline这样的无格式输入函数。这将读取所有字符,直到给定的分隔符并将其存储在 std::string
变量中。分隔符通常是'\n',这样std::getline
会读完整行直到换行符'\n'。但我们也可以指定不同的分隔符,例如 ')' 或其他任何内容。
请记住格式化输入功能 return 对给定字符串的引用。因此,test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6
将导致流 test
。由于 std::getline
需要一个流作为第一个参数,我们可以将完整的长输入语句传递到 std::getline
并写入:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6;
std::string comment;
std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')');
return 0;
}
结果将是
你猜怎么着? std::getline
也 return 流。知道了这一点和上面的内容,我们可以得出一行的最终解决方案。
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6, c7;
std::string comment;
std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7;
return 0;
}
下一步:检查IO操作是否成功。
我们应该始终检查任何 IO 操作的结果。但是怎么办?我已经解释过 IO-operations return 是对流的引用。这样我们就可以写成:
if (std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7) {
...
}
但是怎么办?正如所说。输入函数将 return 引用流,然后我们离开:if (test)
。这行得通,因为流的 bool 运算符被覆盖了(参见 here)。这个 bool 运算符会告诉我们是否有错误。
所以,要读取和输出所有数据,我们可以这样写:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6, c7;
std::string comment;
while (std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7)
std::cout << "Line: " << line << "\tTime: " << time << "\tType: " << type << "\tComment: " << comment << '\n';
}
这表明它基本上是如何工作的。
但是,您需要不同的输出格式。这不是水平的,而是垂直的。因此,我们需要将读取的内容存储在某个动态容器中。我希望你知道 std::vector
。如果没有,请告诉我,我也会在这里帮助你。
所以我们不会读取变量,输出它们然后忘记它,而是存储它们以备后用。
您可能听说过 C++ 是一种所谓的面向对象的语言。在这里,我们将处理这些数据的方法中的数据放入一个 class
或 struct
.
这可能看起来像:
struct LogLine {
int line{};
long time{};
int type{};
std::string comment{};
};
这是数据部分。现在,我们需要这些数据的方法。我们唯一需要的就是输入。为此,我们可以将提取操作 >>
添加到此结构中。语法是:
std::istream& operator >> (std::istream& is, LineInfo& l) { ....
结合我们上面学到的东西我们现在可以写:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
struct LogLine {
// Data
int line{};
long time{};
int type{};
std::string comment{};
// Methods
friend std::istream& operator >> (std::istream& is, LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return std::getline(is >> l.line >> c1 >> c2 >> l.time >> c3 >> c4 >> l.type >> c5 >> c6 >> std::ws, l.comment, ')') >> c7;
}
friend std::ostream& operator << (std::ostream& os, const LogLine& l) {
return os << "Line: " << l.line << "\tTime: " << l.time << "\tType: " << l.type << "\tComment: " << l.comment;
}
};
这要好得多。
现在我们可以为这些数据创建一个 std::vector
甚至更好,将其封装在一个额外的 class.
中
例如:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <vector>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
struct LogLine {
// Data
int line{};
long time{};
int type{};
std::string comment{};
// Methods
friend std::istream& operator >> (std::istream& is, LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return std::getline(is >> l.line >> c1 >> c2 >> l.time >> c3 >> c4 >> l.type >> c5 >> c6 >> std::ws, l.comment, ')') >> c7;
}
friend std::ostream& operator << (std::ostream& os, const LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return os << "Line: " << l.line << "\tTime: " << l.time << "\tType: " << l.type << "\tComment: " << l.comment;
}
};
struct Log {
// Data
std::vector<LogLine> logLines;
// Methods
friend std::istream& operator >> (std::istream& is, Log& l) {
l.logLines.clear(); LogLine tmp{};
while (is >> tmp) l.logLines.push_back(tmp);
return is;
}
friend std::ostream& operator << (std::ostream& os, const Log& l) {
os << "\nLine Of the log : "; for (const LogLine& ll : l.logLines) os << ll.line << ", ";
os << "\nType of the log : "; for (const LogLine& ll : l.logLines) os << ll.type << ", ";
os << "\nTime of the log : "; for (const LogLine& ll : l.logLines) os << ll.time << ", ";
os << "\nComment of the log : "; for (const LogLine& ll : l.logLines) os << ll.comment << ", ";
return os;
}
};
int main() {
Log log;
// Read and parse all data
test >> log;
// Show debug output
std::cout << log;
}
这为您提供了惯用的正确解决方案。
如您所见,我们将一个大问题拆分为许多小问题。先解决输入部分,然后再封装成结构体。
结果是 main 中的一行用于读取和解析整个文件。
如果您有任何问题,我很乐意回答。
我无法解析 .txt 文件中的所有文本 但是当我 运行 我的代码时,我没有得到我想要的:(
我的代码:
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";
}
控制台:
Line Of the log: 1
Type of the log: 1
Time of the log: 111
Comment of the log :text line from 111
我希望解析器读取所有行,但结果完全不同
我不明白我做错了什么,我试图得到以下结果:
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,
请帮忙:(
我建议为此使用正则表达式:
- 下面的示例只是使用给定的模式解析每一行。您可能需要对其进行修改,例如,允许在某些字段周围使用空格。
#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
- 如果您想要不同的输出(例如,您在问题中似乎建议打印所有行号,然后一直打印,依此类推),您可能需要使用
std::vectors
来保持该信息,并在最后打印出来。
#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,
- 尽管您最好使用
struct
中的单个std::vector
,并为数字、类型和时间设置适当的类型。在这种情况下,您需要将字符串从matches
转换为struct
的int
(您可以使用std::stoi
)。
struct LineInfo
{
int number{};
int type{};
int time{};
std::string comment{};
};
std::vector<LineInfo> line_infos{};
阅读您的源代码,我假设您正在学习 C++ iostream 功能。正则表达式之类的东西一开始可能还是太复杂了。因此,让我们尝试使用正常的 iostream 功能生存。
基本上你应该知道有两种主要的输入类型:
- 格式化输入
- 未格式化的输入
要了解概览,请阅读有关 here 的 CPP 参考资料。
您已经了解格式化 IO,因为您一直在使用 std::cout << "Hello" << '\n';
或 std::cin >> word >> count
等语句。格式化输入函数从流中读取字符,解释它们(格式化)并将它们转换为目标类型。例如,如果您输入 int number; std::cin >> number;
,然后按 1、2、3 键,软件将读取字符“1”、“2”和“3”,然后将其转换为整数。
在幕后还有更多内容,但现在这个解释还不错。请注意 IO-operators,就像提取运算符 >>
一样,总是 return 它们被调用的流。这允许链接此类语句。 std::cin >> word >> count
的示例。首先 std::cin >> word
被执行。直到白色 space 之前的所有字符将被读取,然后转换为字符串并存储在 word
中。 >>
操作将 return 调用它的流,在我们的例子中:std::cin
。所以,读完这个词后,我们现在剩下语句 std::cin >> count
了。然后将读取计数。分隔白色 space 将被忽略。这就是它基本起作用的原因和方式。
一个更重要的属性是>>
操作跳过任何潜在的白色space(包括换行符'\n')然后开始转换。如果读取的字符不能再转换为目标变量,它将停止读取和使用输入流中的字符。这又包括白色 space.
如果流中有 1/ [111]{1}(text line from 111);
并写入 stream >> number;
,那么它将读取字符 1 并开始转换为整数。然后它会看到以下“/”字符。它停止读取并将“1”转换为数字 1,但是,它不会从流中提取“/”。它仍然存在,可以而且必须阅读。因此,如果我们定义一个 char
变量 c1
并写入 stream >> number >> c1
那么首先数字将被读取为 number
并且 '/' 将被读取为 c1
.空格将被忽略。
通过使用这种机制,您可以像这样读取字符串的第一部分:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6;
std::string comment;
test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6;
return 0;
}
(cx 变量只是虚拟变量)
变量将是:
这符合预期。空间不会以任何方式打扰这里。
现在是下一部分,注释,所以字符串中的 text line from 111
。如您所见,它包含 spaces。并且由于格式化输入函数在白色 space 处停止转换,我们不能使用像 >>
这样的格式化输入函数将完整的文本读入一个字符串变量。
现在我们需要使用像std::getline这样的无格式输入函数。这将读取所有字符,直到给定的分隔符并将其存储在 std::string
变量中。分隔符通常是'\n',这样std::getline
会读完整行直到换行符'\n'。但我们也可以指定不同的分隔符,例如 ')' 或其他任何内容。
请记住格式化输入功能 return 对给定字符串的引用。因此,test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6
将导致流 test
。由于 std::getline
需要一个流作为第一个参数,我们可以将完整的长输入语句传递到 std::getline
并写入:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6;
std::string comment;
std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')');
return 0;
}
结果将是
你猜怎么着? std::getline
也 return 流。知道了这一点和上面的内容,我们可以得出一行的最终解决方案。
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6, c7;
std::string comment;
std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7;
return 0;
}
下一步:检查IO操作是否成功。
我们应该始终检查任何 IO 操作的结果。但是怎么办?我已经解释过 IO-operations return 是对流的引用。这样我们就可以写成:
if (std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7) {
...
}
但是怎么办?正如所说。输入函数将 return 引用流,然后我们离开:if (test)
。这行得通,因为流的 bool 运算符被覆盖了(参见 here)。这个 bool 运算符会告诉我们是否有错误。
所以,要读取和输出所有数据,我们可以这样写:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
int main() {
int line, time, type;
char c1,c2,c3,c4,c5,c6, c7;
std::string comment;
while (std::getline(test >> line >> c1 >> c2 >> time >> c3 >> c4 >> type >> c5 >> c6, comment, ')') >> c7)
std::cout << "Line: " << line << "\tTime: " << time << "\tType: " << type << "\tComment: " << comment << '\n';
}
这表明它基本上是如何工作的。
但是,您需要不同的输出格式。这不是水平的,而是垂直的。因此,我们需要将读取的内容存储在某个动态容器中。我希望你知道 std::vector
。如果没有,请告诉我,我也会在这里帮助你。
所以我们不会读取变量,输出它们然后忘记它,而是存储它们以备后用。
您可能听说过 C++ 是一种所谓的面向对象的语言。在这里,我们将处理这些数据的方法中的数据放入一个 class
或 struct
.
这可能看起来像:
struct LogLine {
int line{};
long time{};
int type{};
std::string comment{};
};
这是数据部分。现在,我们需要这些数据的方法。我们唯一需要的就是输入。为此,我们可以将提取操作 >>
添加到此结构中。语法是:
std::istream& operator >> (std::istream& is, LineInfo& l) { ....
结合我们上面学到的东西我们现在可以写:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
struct LogLine {
// Data
int line{};
long time{};
int type{};
std::string comment{};
// Methods
friend std::istream& operator >> (std::istream& is, LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return std::getline(is >> l.line >> c1 >> c2 >> l.time >> c3 >> c4 >> l.type >> c5 >> c6 >> std::ws, l.comment, ')') >> c7;
}
friend std::ostream& operator << (std::ostream& os, const LogLine& l) {
return os << "Line: " << l.line << "\tTime: " << l.time << "\tType: " << l.type << "\tComment: " << l.comment;
}
};
这要好得多。
现在我们可以为这些数据创建一个 std::vector
甚至更好,将其封装在一个额外的 class.
例如:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <vector>
std::istringstream test{ R"(1/[111]{1}(text line from 111);
2/ [222]{2}(text line from 222);
3/ [333]{3}(text line from 333);)" };
struct LogLine {
// Data
int line{};
long time{};
int type{};
std::string comment{};
// Methods
friend std::istream& operator >> (std::istream& is, LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return std::getline(is >> l.line >> c1 >> c2 >> l.time >> c3 >> c4 >> l.type >> c5 >> c6 >> std::ws, l.comment, ')') >> c7;
}
friend std::ostream& operator << (std::ostream& os, const LogLine& l) {
char c1, c2, c3, c4, c5, c6, c7;
return os << "Line: " << l.line << "\tTime: " << l.time << "\tType: " << l.type << "\tComment: " << l.comment;
}
};
struct Log {
// Data
std::vector<LogLine> logLines;
// Methods
friend std::istream& operator >> (std::istream& is, Log& l) {
l.logLines.clear(); LogLine tmp{};
while (is >> tmp) l.logLines.push_back(tmp);
return is;
}
friend std::ostream& operator << (std::ostream& os, const Log& l) {
os << "\nLine Of the log : "; for (const LogLine& ll : l.logLines) os << ll.line << ", ";
os << "\nType of the log : "; for (const LogLine& ll : l.logLines) os << ll.type << ", ";
os << "\nTime of the log : "; for (const LogLine& ll : l.logLines) os << ll.time << ", ";
os << "\nComment of the log : "; for (const LogLine& ll : l.logLines) os << ll.comment << ", ";
return os;
}
};
int main() {
Log log;
// Read and parse all data
test >> log;
// Show debug output
std::cout << log;
}
这为您提供了惯用的正确解决方案。
如您所见,我们将一个大问题拆分为许多小问题。先解决输入部分,然后再封装成结构体。
结果是 main 中的一行用于读取和解析整个文件。
如果您有任何问题,我很乐意回答。