[英]Best way to read a files contents and separate different data types into separate vectors in C++
我對 C++ 語法相當陌生,想知道是否有人可以提供他們將如何解決我遇到的問題。
我的任務是讀取包含字符串和整數組合的文件 txt 內容。 然后我需要將所有整數存儲到一個向量中,並將所有字符串存儲到另一個向量中。 我已經設法將所有內容存儲到一個向量中,但現在我想將不同的數據類型分成它們自己的向量,但是我正在努力尋找最好的方法。 我會遍歷整個向量,然后使用數據類型的 if 條件,還是有其他方法? 我已經發布了我讀取文件代碼和文件的示例,以便您更清楚地理解我的意思。
謝謝,
// Basic read file code
fstream file("filepath.txt", ios::in); // reads file
string line; // temp storage of lines in file
vector<string> lines; // creates for permanent storage
while (getline(file, line))
{
lines.push_back(line);
}; // pushes each line to back of vector until file end.
文件示例 - 每個字符串都是一個問題,下面的行作為 int 的答案。 一共88行。
1, string"
2, int
3,"string"
4, int
5,"string"
6, int
你快到了,你的例子中的代碼很好。 只是錯過了第二步:
// storage
std::vector<int> integers;
std::vector<std::string> strings;
// open file and iterate
std::ifstream file( "filepath.txt" );
while ( file ) {
// read one line
std::string line;
std::getline(file, line, '\n');
// create stream for fields
std::istringstream ils( line );
std::string token;
// read integer (I like to parse it and convert separated)
if ( !std::getline(ils, token, ',') ) continue;
int ivalue;
try {
ivalue = std::stoi( token );
} catch (...) {
continue;
}
integers.push_back( ivalue );
// Read string
if ( !std::getline( ils, token, ',' )) continue;
strings.push_back( token );
}
神栓: https://godbolt.org/z/4aMv6MW4K
順便說一句, using std;
練習可以在未來咬你。 盡量在代碼中保留std::
前綴,這樣更安全。
您應該交替創建兩個向量和 push_back 數據,希望對您有所幫助:)
你在這里問你應該如何處理給定的問題。
在正常的軟件開發中,我們會執行幾個步驟。 首先,我們分析需求,然后考慮設計,然后開始編碼。 最后,我們驗證並驗證該計划。 實際上還有更多的過程。 但請采納一項重要建議:
在寫代碼之前。 我們應該先弄清楚“是什么”,然后是“如何”。
最后但並非最不重要的一點是,在進行編碼時,我們應該遵循標准模式以避免最常見的問題。
所以,現在讓我們看看你的問題。 你想讀一個文本文件。 文本文件包含帶有逗號分隔值的行。 用逗號分隔值的行應被拆分。
然后,總是有 2 條線屬於一起。 第一行包含索引作為 integer 數字和問題作為字符串,第二行還包含一個 integer 索引,然后是一個 integer 數字表示答案。
應讀取並存儲所有數據以供進一步處理。
在這個時間點上,我們總體上已經完成了需求分析。
接下來是“如何”,設計,“我們想怎么做”
您提到您想使用 2 個不同的向量來存儲問題和答案。 這種方法基本上不是那么好。
因為一般規則是,您應該以某種方式將屬於一起的值存儲在“結構”或“類”中,甚至具有不同的類型,例如 int 和 string。 這同樣適用於第一行中的數據,然后是下一行中的數據。
另一方面,許多具有相同類型的數據應存儲在容器中,如std::array
或std::vector
(或其他,取決於用例)。
在您的情況下,您將兩者兼而有之。 因此,首先是struct
中具有不同類型的數據,然后是這些結構的std::vector
。
上述示例(許多可能的解決方案之一):
#include <iostream>
#include <vector>
struct Question {
int index{};
std::string text{};
};
struct Answer {
int index{};
int data{};
};
struct QuestionAndAnswer {
Question question{};
Answer answer{};
};
std::vector<QuestionAndAnswer> questionAndAnswer{};
好的,接下來明白了。
我們要打開一個文件並逐行讀取它。 打開一個文件進行讀取,可以通過定義一個std::ifstream
然后將一個文件名交給它的構造函數來完成。 這將為您打開文件。 最后,當std::ifstream
類型的變量超出 scope 時, std::ifstream
的析構函數會自動為您關閉文件。
對於 C++ 功能的任何問題,您應該始終查看 CPP 參考。
作為一般規則,您應該始終檢查任何 IO 操作的結果。 這可以通過if (ifstreamVaraible)
來完成。 如果查看 IO-Stream 函數的定義,您會發現其中許多函數再次返回對已調用的 IO-Stream 的引用。 例子:
// Open the file
std::ifstream sourceFileStream(“test.txt”);
// Check, if it could be opened successfully
if (sourceFileStream) {
// Read the line and get the result
std::string line{};
if (std::getline(sourceFileStream, line)) {
. . .
}
這是如何運作的? 如果您查看 stream 函數的文檔,那么您會看到它們的bool
而不是 operator !
被覆蓋並返回 stream 的狀態。 對於上面的示例if (sourceFileStream) {
編譯器在if
語句中看到 stream 變量,它是否需要 boolean 表達式。 然后它將采用 stream 的bool
function 並對其進行評估。
同樣適用於if (std::getline(sourceFileStream, line))
。 這將首先執行getline
- 操作,該操作將讀取該行。 然后getline
返回對 stream 的引用。 然后if
- 語句再次包含准if (sourceFileStream)
和 bool 運算符將被調用。
使用這種機制,您可以(並且應該)檢查所有 IO 操作的結果。
如果我們想在一個循環中讀取多行,那么規則是將std::getline(sourceFileStream, line)
語句放入 while 語句條件部分。 否則你總是會讀太多。
你會從不那么有經驗的開發人員那里經常看到類似 'while (.sourceFileStream,eof())' 或類似的while (sourceFileStream)
的東西。 這被認為是錯誤的。 她有很多關於 SO 的陳述,更詳細地解釋了這一點。
接下來,如果您想學習 C++ 並使用更好的方法,那么您應該使用面向對象編程。 第一步是將數據和對該數據進行操作的方法放在一個class
或struct
中。 對於您的情況,這意味着輸入函數應該是結構的一部分。
在 C++ 中,輸入是通過提取運算符>>
完成的。 因此我們應該在你的結構中添加一個提取器操作符。
其語法是(以答案 struct= 為例:
struct Answer {
int index{};
int data{};
friend std::istream& operator >> (std::istream& is, Answer& a) {
// Read an index, a comma, and the answer
char comma{};
return is >> a.index >> comma >> a.data;
}
};
This is a function for the class
(or struct
) “Answer”, that takes a stream and an answer as input and will return again a reference to the stream. 現在,我們可以寫:
Answer answer{};
if (!(std::cin >> answer))
std::cerr << “Problem while reading answer\n”;
if
- 語句將執行嵌入式提取操作。 編譯器將看到一個 stream、提取運算符>>
和一個 Answer 類型的變量。 因此,它將調用上述結構中定義的 function。 該操作將返回對 stream 的引用和!
stream 的操作員將指示,如果 stream ha 和問題。
output 可以實現類似的機制,因此我們也可以覆蓋插入操作符>>
。
綜上所述,我們可以將上述大問題分解為非常小的單元,這些單元可以以簡單易懂的方式實現。
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iomanip>
struct Question {
// Data
int index{};
std::string text{};
// Extractor operator
friend std::istream& operator >> (std::istream& is, Question& q) {
char comma{};
// First read the index, then the comma, then eat up white space. A reference to is will be returned. getline
// will read the rest of the line by using is. It will also return is, which is then the function return value
return std::getline(is >> q.index >> comma >> std::ws, q.text);
}
// Simple output
friend std::ostream& operator << (std::ostream& os, const Question& q) {
return os << "Question: Index: " << q.index << "\tText: " << q.text;
}
};
struct Answer {
// Data
int index{};
int data{};
// Extractor operator
friend std::istream& operator >> (std::istream& is, Answer& a) {
char comma{};
// Read the index, then the comma, then data. A reference to is will be returned.
return is >> a.index >> comma >> a.data;
}
// Simple output
friend std::ostream& operator << (std::ostream& os, const Answer& a) {
return os << "Answer: Index: " << a.index << "\tData: " << a.data;
}
};
struct QuestionAndAnswer {
// Data
Question question{};
Answer answer{};
// Extractor operator
friend std::istream& operator >> (std::istream& is, QuestionAndAnswer& q) {
// Read question and answer
return is >> q.question >> q.answer;
}
// Simple output
friend std::ostream& operator << (std::ostream& os, const QuestionAndAnswer& q) {
return os << q.question << "\t\t" << q.answer;
}
};
int main() {
// Here we will store all questions and answers
std::vector<QuestionAndAnswer> questionAndAnswer{};
// Open the source file and check, if it could be opened
std::ifstream sourceFileStream("r:\\filepath.txt");
if (sourceFileStream) {
QuestionAndAnswer temp{};
// Read all questions and answers in a loop
while (sourceFileStream >> temp)
questionAndAnswer.push_back(temp);
// Show debug output
for (const QuestionAndAnswer& qa : questionAndAnswer)
std::cout << qa << '\n';
}
else
std::cerr << "\nError: Could not open source file\n";
}
使用這種方法將是 c++ 編程器的眾多推薦方法之一。
包含的源文件
1, Question 1
2, 1
3, Question 2
4, 2
5, Question 3
6, 3
7, Question 4
8, 4
9, Question 5
10, 5
將創建 output:
Question: Index: 1 Text: Question 1 Answer: Index: 2 Data: 1
Question: Index: 3 Text: Question 2 Answer: Index: 4 Data: 2
Question: Index: 5 Text: Question 3 Answer: Index: 6 Data: 3
Question: Index: 7 Text: Question 4 Answer: Index: 8 Data: 4
Question: Index: 9 Text: Question 5 Answer: Index: 10 Data: 5
如果你想堅持你原來的想法,那么你可以使用:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iomanip>
int main() {
// Here we will store all questions and answers
std::vector<std::string> questions{};
std::vector<int> answers{};
// Open the source file and check, if it could be opened
std::ifstream sourceFileStream("r:\\filepath.txt");
if (sourceFileStream) {
std::string question{};
int temp{}, answer{};
char comma{};
// Read all questions and answers in a loop
while (std::getline(sourceFileStream >> temp >> comma >> std::ws, question))
if (sourceFileStream >> temp >> comma >> answer) {
// We do not want to go out fo sync. Always store questions and answers together
questions.push_back(question);
answers.push_back(answer);
}
// Debug output
for (unsigned int k = 0; k < questions.size(); ++k)
std::cout << "Question: " << questions[k] << "\t\tAnswer: " << answers[k] << '\n';
}
else
std::cerr << "\nError: Could not open source file\n";
}
但也許不那么推薦......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.