簡體   English   中英

在 C++ 中讀取文件內容並將不同數據類型分成不同向量的最佳方法

[英]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::arraystd::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++ 並使用更好的方法,那么您應該使用面向對象編程。 第一步是將數據和對該數據進行操作的方法放在一個classstruct中。 對於您的情況,這意味着輸入函數應該是結構的一部分。

在 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM