如何从仅使用空格作为分隔符的文件中获取要写入的二维数组

Posted

技术标签:

【中文标题】如何从仅使用空格作为分隔符的文件中获取要写入的二维数组【英文标题】:How to get a 2D array to write from a file with only spaces used as separators 【发布时间】:2018-12-08 06:38:16 【问题描述】:

我正在尝试获取一个文件并将其放入 3 个不同的数组中。其中两个数组是一维数组,另一个是二维数组。文本文件如下

Bill Hansley 1 1 1 1 1
Todd Howard 2 3 1 0 0
Sam Duke 0 1 1 0 0
Danny Martin 1 0 2 0 1

我正在尝试获取这个文本文件,并将名字插入到名为 firstNames[] 的数组中,然后将另一个用于姓氏的数组称为 lastNames[],最后将数字插入到数组中称为 Productsorders[][]。我的代码如下。

bool loadOrderFile(string orderFN,
    string firstNames[], string lastNames[],
    int productsOrders[MAX_ORDERS][MAX_PRODS],
    int &namesCount, int &prodCount, string &menuName) 

    ifstream File;
    File.open(orderFN.c_str());
    if (File.is_open()) 
        cout << "Order file opened..." << endl;
    
    int i = 0;
    getline(File, menuName);
    (File >> prodCount);
    while (File) 
        File.get();
        (File >> firstNames[i]);
        (File >> lastNames[i]);
        (File >> productsOrders[i][i]);
        (File >> productsOrders[i + 1][i + 1]);
        (File >> productsOrders[i + 2][i + 2]);
        (File >> productsOrders[i + 3][i + 3]);
        (File >> productsOrders[i + 4][i + 4]);

        (i++);
    
    cout << "Menu name: " << menuName << endl;
    cout << "Product Count: " << prodCount << endl;
    cout << "There were " << (prodCount - 1) << " orders read in." << endl;
    for (int i = 0; i < 10; i++) 
        cout << productsOrders[i][i] << endl;
    
    for (int i = 0; i < 10; i++) 
        cout << firstNames[i] << lastNames[i] << endl;
    
    return true;

名称数组似乎可以正常工作,因为它们按应有的方式输出名称,但二维数组输出

1
2
0
1
0
2
0
1
0
0

应该是什么时候

1 1 1 1 1
2 3 1 0 0
0 1 1 0 0
1 0 2 0 1

我将不胜感激。

【问题讨论】:

您从文件内容中显示的信息;内容之前有标题信息吗?还是从您显示的文件开始?我看到你有一个getline() 调用menuName,然后从文件中提取prodCount,最后在你的while 循环中你有一个fstream::get() 调用,然后你开始填充你的数组。只是想更好地理解您的文件结构以尝试正确解析它。 【参考方案1】:

你的问题是你在这里没有正确处理你的二维数组。

例如,在3x3 二维数组中,您有两个索引[a][b],该数组的二维表示如下所示:

[0][0] [0][1] [0][2]

[1][0] [1][1] [1][2]

[2][0] [2][1] [2][2]

所以当你输出例如:

for (int i = 0; i < 10; i++) 
    cout << productsOrders[i][i] << endl;

你可以看到你只会得到一条穿过数组的对角线,而不是所有的项目 ([0][0], [1][1], [2][2])。要打印整个数组,您需要使用两个循环。

您的输入存在类似问题,您同时增加了两个索引。

【讨论】:

【参考方案2】:

在解析文本文件时诚实;我会根据其独特的职责将逻辑分成单独的功能。

你的代码看起来像这样:

#include <vector>
#include <string>
#include <sstream> 
#include <iostream>
#include <fstream>
#include <exception>

// Structure of your data type...
struct Order 
    std::string firstName;
    std::string lastName;
    std::vector<int> productOrders; // maybe use vector instead of array...
    // any other variable(s) or container(s) you may need...
;

// Simple ostream operator<< overload to print your Order Struct
// in a nice readable format.
std::ostream& operator<<(std::ostream& os, const Order& order ); 

// Function to split a string based on a single character delimiter
std::vector<std::string> splitString( const std::string& s, char delimiter );

// Function that will get each line text from a file and stores it into a vector
// of strings. Then closes the file handle once the entire file has been read.
void getAllLinesFromFile(const char* filename, std::vector<std::string>& output);

// This function will parse a single line of text or string that is contained in 
// the vector of strings. The declaration of this can vary; if you have other
// information such as header information before the actual data structures
// you would have to modify this function's declaration-definition to accommodate
// for those variables. 
void parseLine( const std::vector<std::string>& fileContents, std::vector<Order>& orders );

// Simple and clean looking main function.
int main() 
    try 
        std::vector<std::string> fileContents;
        getAllLinesFromFile( "filename.txt", fileContents );
        std::vector<Order> orders;
        parseLine( fileContents, orders );

        for ( auto& o : orders )
            std::cout << o << '\n';           

     catch( std::runtime_error& e ) 
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    
    return EXIT_SUCCESS;



std::ostream& operator<<(std::ostream& os, const Order& order ) 
    os << order.firstName << " " << order.lastName << '\n';    
    for (auto& p : order.productOrders)
        os << p << " ";
    os << '\n';
    return os;



std::vector<std::string> splitString( const std::string& s, char delimiter ) 
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream( s );
    while( std::getline( tokenStream, token, delimiter ) ) 
        tokens.push_back( token );
    

    return tokens;


void getAllLinesFromFile(const char* filename, std::vector<std::string>& output) 
    std::ifstream file(filename);
    if (!file) 
        std::stringstream stream;
        stream << "failed to open file " << filename << '\n';
        throw std::runtime_error(stream.str());
     else 
        std::cout << "File " << filename << " opened successfully.\n";
    

    std::string line;
    while (std::getline(file, line)) 
        if (line.size() > 0)
            output.push_back(line);
    
    file.close();


void parseLine( const std::vector<std::string>& fileContents, std::vector<Order>& orders ) 
    // Here is where you would do the logic to parse the vector of strings
    // this function may vary based on your file structure. If there is any
    // header information you would have to extract that first from the 
    // vector's index. 

    // Once you get to the index in the vector that describes your data structure
    // it is hear that you would want to call `splitString()` using the current
    // current index of that vector and the space character as your delimiter.
    // This will create a vector of strings that are now considered to be tokens.

    // On each pass of the loop for each line of contents you will want to
    // create an instance of the Order Structure, then use that to populate
    // the vector of Orders that was passed in by reference.

    // Once all of the contents are done being parsed the function will exit
    // and your vector of Orders will have the appropriate data.    

在解析文本文件时,拥有这种结构会更容易调试。我相信从文件中检索所有数据并将其存储到某个容器中会更优雅;最容易使用的是string,或者一些stream buffer,例如stringstream。完成所有内容后关闭文件。从文本文件中读取所有内容并将其存储到字符串容器中之后。这是您想要解析stringsstreams 并检查信息是否有效的地方。多次打开和关闭文件句柄效率低下且速度慢,而且可能会出错。我认为从文件中获取内容、保存、关闭并完成文件,然后继续实际工作会更容易。

【讨论】:

以上是关于如何从仅使用空格作为分隔符的文件中获取要写入的二维数组的主要内容,如果未能解决你的问题,请参考以下文章

添加一个双空格作为分隔符

如何在php中解析带有空格的空格分隔字符串?

如何基于多个空格字符将文本文件拆分为 2 列作为 scala spark 的分隔符

opencsv写入时去掉双引号

在R中读取具有多个空格作为分隔符的文本文件

将文本写入文件,包括空格