簡體   English   中英

如何從 C++ 中的文件中讀取用逗號分隔的全名?

[英]How do I read a full name that is separated by a comma from a file in C++?

我試圖從我要求用戶輸入的文件中讀取用逗號分隔的全名。在示例中,我將提交它是關於美國前十位總統的。 這是我的代碼(我有所有必要的庫,我只是顯示主要的 function 以便我可以知道我錯在哪里):

 int main()
{
    const int NUMBER_OF_PRESIDENTS = 50;
    int n = 0;
    string president[NUMBER_OF_PRESIDENTS];

    string fileName;
    ifstream inputFile;

    cout << "Enter name of input file ";
    getline(cin, fileName);

    inputFile.open(fileName.c_str());

    if (inputFile.fail()) {
        cout << "This file does not exist.";
    }

    if (inputFile >> president[n]) {
        n++;
    }

    cout << n << " lines of text read from the input file.\n"
        << "Here are the unsorted names:\n"
        << "--------------------------- \n";

    for (int i = 0; i < n; i++) {
        cout << "[" << (i+1) << "] " << president[i] << endl;
    }

    return 0;
}

用戶輸入一個 txt 文件名“firstTen.txt”,並顯示以下 txt:

Washington, George
Adams, John
Jefferson, Thomas
Madison, James
Monroe, James
Adams, John Quincy
Jackson, Andrew
Van Buren, Martin
Harrison, William Henry
Tyler, John

我的問題是我希望它讀取每一行,然后將 go 讀取到下一任總統的名字。 但是,當它顯示時,它只顯示如下: 在此處輸入圖像描述

從輸入文件 stream 讀取時,您應該像這樣讀取整行:

if (getline(inputFile, president[n])) {
    n++;
}

代替:

if (inputFile >> president[n]) {
    n++;
}

要遍歷所有名稱,您可以執行以下操作:

int index = 0;
while (getline(inputFile, president[index])) {
    index++;
}

請注意,由於您稍后使用n進行循環,因此您應該使用另一個變量進行索引。

inputFile >> president[n]最多只能讀取第一個空白字符。 但是, std::getline會讀取包括任何空格在內的整行。

您還需要遍歷輸入文件中的行,因此請執行以下操作:

while (getline(inputFile, president[n])) {
    n++;
}

使用ifstream從文件中讀取數據。

要逐行閱讀,您可以這樣做:

for( std::string line; getline( input, line ); )
{
    ...for each line in input...
}

你也可以這樣做

if (file.is_open()) {
    std::string line;
    while (std::getline(file, line)) {
// your logic
}
    file.close();
}

我會使用“更現代”的 C++ 方法。

我們想閱讀有關總統的數據。 因此,我們創建了一個微小的 class “總統”,只包含名字和姓氏。 因為 class 知道如何讀寫它的數據,我們將覆蓋插入器和提取器操作符。

基本上你想讀一個 csv 文件。

仍然所有人都在鏈接到“我如何閱讀和解析 C++?2 中的 CSV 文件?SO。但是,問題是從 2009 年開始,現在已經超過 10 年了。大多數答案也很老而且非常復雜。所以,也許是時候了改變。

在現代 C++ 中,您擁有迭代范圍的算法。 你會經常看到類似“someAlgoritm(container.begin(), container.end(), someLambda)”的東西。 這個想法是我們迭代一些相似的元素。

在您的情況下,我們遍歷輸入字符串中的標記,並創建子字符串。 這稱為標記化。 我們這樣做是為了從以逗號分隔的文件中獲取名稱和名字。

正是為了這個目的,我們有std::sregex_token_iterator 而且因為我們有為此目的而定義的東西,我們應該使用它。

這東西是一個迭代器。 用於迭代字符串,因此是正則表達式。 開始部分定義了我們將操作的輸入范圍,然后有一個std::regex用於在輸入字符串中應該匹配/不應該匹配的內容。 匹配策略的類型由最后一個參數給出。

  • 1 --> 給我我在正則表達式中定義的東西和
  • -1 --> 告訴我根據正則表達式不匹配的內容。

所以,既然我們了解了迭代器,我們就可以將標記從迭代器復制到我們的目標,即std::stringstd::vector 由於我們不知道我們有多少列,我們將使用std::vector的范圍構造函數。 簡單的。

下一步。 我們想從文件中讀取。 該文件還包含某種相同的數據。 相同的數據是行。

如上所述,我們可以迭代相似的數據。 如果是文件輸入或其他。 為此, C++ 具有std::istream_iterator 這是一個模板,作為模板參數,它獲取應讀取的數據類型,作為構造函數參數,它獲取對輸入 stream 的引用。 沒關系,如果輸入 stream 是std::cinstd::ifstreamstd::istringstream 所有類型的流的行為都是相同的。

由於我們沒有 SO 文件,因此我使用(在下面的示例中) std::istringstream來存儲輸入 csv 文件。 當然,您可以通過定義std::ifstream sourceFile(filename)打開文件。 沒問題。

使用std::istream_iterator ,我們遍歷輸入並讀取相似的數據。 在我們的例子中,一個問題是我們想要迭代特殊數據而不是一些內置數據類型。 為此,我們使用 class 總統和覆蓋的提取器和插入器操作符-

所以我們定義了一個變量president並使用它的范圍構造函數並給它一個范圍的開始和一個范圍的結束。 而且,在我們的具體示例中,我們使用std::istream_iterator的開始和結束迭代器。

如果我們結合以上所有內容,閱讀完整的 CSV 文件是單行的,它是調用其構造函數的變量的定義。

請查看生成的代碼:

#include <iostream>
#include <sstream>
#include <string>
#include <regex>
#include <vector>
#include <iterator>

const std::regex re(",");

std::istringstream sourceFile{R"(
Washington, George
Adams, John
Jefferson, Thomas
Madison, James
Monroe, James
Adams, John Quincy
Jackson, Andrew
Van Buren, Martin
Harrison, William Henry
Tyler, John)"};

struct President {
    // Data, at this moment: "name" and "firstName"
    std::string name{};
    std::string firstName{};

    // Overwrite extractor 
    friend std::istream& operator >> (std::istream& is, President& p) {

        // We will read one line
        std::string line{};
        if (getline(is, line)) {
            // Iterator to iterate over the comma separated field in the input string
            std::vector<std::string> data {std::sregex_token_iterator(line.begin(), line.end(), re, -1),std::sregex_token_iterator()};
            // Read name and first name. Easy to add more
            p.name = data[0]; 
            p.firstName = data[1];
        }
        return is;
    }

    // Overwrite inserter operator
    friend std::ostream& operator << (std::ostream& os, const President& p) {
        return os << p.firstName << " " << p.name;
    }
};

int main()
{
    // Read the complete source file into a std::vector
    std::vector<President> president {std::istream_iterator<President>(sourceFile),std::istream_iterator<President>()};

    // Show result on console
    std::copy(president.begin(), president.end(), std::ostream_iterator<President>(std::cout, "\n"));

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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