简体   繁体   English

C ++:将文本文件解析并读取为多个由分号分隔的数组

[英]c++: parsing and reading text file into multiple arrays separated by delimters

Good afternoon everyone, 大家下午好,

Firstly, thank you for taking your time into inputting and helping me understand my problem. 首先,感谢您花费时间输入和帮助我理解我的问题。 I will disclose that this is a Assignment problem so i would like to understand it rather than be given the full code. 我将披露这是一个分配问题,因此我想了解它而不是获得完整的代码。

As per the title of the question, I am trying to design a program for my assignment. 按照问题的标题,我正在尝试为我的作业设计一个程序。 I have included the information below. 我已包含以下信息。

Write a program to manage DVD rental in a video rental store. Create
an abstract data type that represents a DVD in this store. Consider all
the data and operations that may be necessary for the DVD type to
work well within a rental management system. Include a print()
member function that displays all the information about the DVD. Test
your data type by creating an array of ten DVD instances and filling
them using information read from a test input file that you create.
Display the DVD information.

Here is what i have so far: 这是我到目前为止所拥有的:


#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main()
{
    string mArrayO[10]; //create array of 10 string objects
    string filename = "testfile.txt";
    ifstream file(filename.c_str()); //// open file constructor because the constructor for an ifstream takes a const char*, not a string in pre C++11
    // go through array till index 10
     for( int x=0; x< 10; x++)
        {
            getline(file, mArrayO[x]); //get line and store into array
            cout << "Line "<< x<<":"<< mArrayO[x]<<endl; //display
        }


    return 0;
}

So far my output is : 到目前为止,我的输出是:

Line:0 Lord of the rings|2005|Fantasy|126 minutes|PG-13
Line:1 Titanic|1997|Romance|104 minutes|R
Line:2 Shawshank Redemption|1993|Drama|120 minutes|R
Line:3 The Lion King|1987|Cartoon|84 minutes|PG-10
Line:4 The God Father|1988|Violence|146 minutes|R
Line:5 Bruce Almighty|2009|Comedy|78 minutes|R
Line:6 Spiderman|2006|Action|84 minutes|PG-13
Line:7 Finding Nemo|2007|Cartoon|87 minutes|E
Line:8 The Martian|2015|SciFi|104 minutes|PG-13
Line:9 Insidious 3|2015|Horror|97 minutes|R 

So as you can see i have put the data into one array. 如您所见,我将数据放入一个数组中。 Now here is what i am trying to do. 现在这就是我想要做的。 I want to be able to parse through this data and feed it into my DVD class. 我希望能够解析这些数据并将其输入到我的DVD类中。 Specifically as my question outlines I want to be able to put all the movie names in one array, dates in another and so on until every data set is matched.Once that is done i want to be able to prompt the user to pick an option and from there have the corresponding function occur. 具体来说,我希望能够将所有电影名称放在一个数组中,将日期放在另一个数组中,以此类推,直到每个数据集都匹配为止。完成后,我希望能够提示用户选择一个选项并从那里有相应的功能发生。

I also have made the following template for my DVD class: 我还为我的DVD类制作了以下模板:

class movie
{
public:
    /// These are our methods to get the information 

string getMovieName()
{
    return moviename;
}

string getYear()
{
    return year;
}

string getGenre()
{
    return genre;
}

string getTime()
{
    return time;
}

string getRating()
{
    return rating;
}  

private: // these are the members of this class. private://这些是此类的成员。 They will store all the information we need for this class string moviename; 它们将存储我们为此类字符串moviename所需的所有信息。 string year; 弦年 string genre; 弦乐类型 string time; 弦时间 string rating; 字符串评级;
}; };

Here is another portion of my code. 这是我代码的另一部分。 I have put it here incase people needed to see if i have attempted 我把它放在这里,以防人们需要看看我是否尝试过

bool done= false; // Client wants to continue.

    while (!done)
    {
        cout<< "This is a test";
        cin.ignore();

    done=ask_to_continue(); 
    }

    //finish
    cout<< "Thank you for using the DVD rental management system";
    return 0;

bool ask_to_continue()
{
   char again; //using keystroke 
   cout << "Do you need more help? Y or N? " << endl;
   cin >> again; 

   if(again == 'n')
      return true; // Exit program

   return false; // Still using program
}

You have successfully read in the data from your text file and populated your array of strings. 您已成功从文本文件中读取数据,并填充了字符串数组。 Now what you need to do is to write a parsing function that will parse each string or line in your array. 现在,您需要编写一个解析函数来解析数组中的每个字符串或行。 Then while parsing each line you will then need to save each content into your class. 然后,在解析每一行时,您将需要将每个内容保存到您的类中。

I can offer you a generic function that will parse strings for you provided that you are using the same delimiter; 我可以为您提供一个通用函数,如果您使用相同的定界符,它将为您解析字符串。 it is encapsulated in a Utility class as a static method along with a few other useful string manipulation functions. 它与其他一些有用的字符串操作函数一起作为静态方法封装在Utility类中。

Utility.h 实用程序

#ifndef UTILITY_H
#define UTILITY_H

class Utility {
public:
    static void pressAnyKeyToQuit();

    static std::string  toUpper( const std::string& str );
    static std::string  toLower( const std::string& str );
    static std::string  trim( const std::string& str, const std::string elementsToTrim = " \t\n\r" );

    static unsigned     convertToUnsigned( const std::string& str );
    static int          convertToInt( const std::string& str );
    static float        convertToFloat( const std::string& str );

    static std::vector<std::string> splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true ); 

private:
    Utility(); // Private - Not A Class Object
    Utility( const Utility& c ); // Not Implemented
    Utility& operator=( const Utility& c ); // Not Implemented

    template<typename T>
    static bool stringToValue( const std::string& str, T* pValue, unsigned uNumValues );

    template<typename T>
    static T getValue( const std::string& str, std::size_t& remainder );

}; // Utility

#include "Utility.inl"

#endif // UTILITY_H

Utility.inl 实用工具

// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
    int numCommas = std::count(str.begin(), str.end(), ',');
    if (numCommas != uNumValues - 1) {
        return false;
    }

    std::size_t remainder;
    pValue[0] = getValue<T>(str, remainder);

    if (uNumValues == 1) {
        if (str.size() != remainder) {
            return false;
        }
    }
    else {
        std::size_t offset = remainder;
        if (str.at(offset) != ',') {
            return false;
        }

        unsigned uLastIdx = uNumValues - 1;
        for (unsigned u = 1; u < uNumValues; ++u) {
            pValue[u] = getValue<T>(str.substr(++offset), remainder);
            offset += remainder;
            if ((u < uLastIdx && str.at(offset) != ',') ||
                (u == uLastIdx && offset != str.size()))
            {
                return false;
            }
        }
    }
    return true;
} // stringToValue

Utility.cpp Utility.cpp

#include "stdafx.h"
#include "Utility.h"

// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
    std::cout << "Press any key to quit" << std::endl;
    _getch();
} // pressAnyKeyToQuit

// toUpper()
std::string Utility::toUpper(const std::string& str) {
    std::string result = str;
    std::transform(str.begin(), str.end(), result.begin(), ::toupper);
return result;
} // toUpper

// toLower()
std::string Utility::toLower(const std::string& str) {
    std::string result = str;
    std::transform(str.begin(), str.end(), result.begin(), ::tolower);
    return result;
} // toLower

// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim(const std::string& str, const std::string elementsToTrim) {
    std::basic_string<char>::size_type firstIndex = str.find_first_not_of(elementsToTrim);
    if (firstIndex == std::string::npos) {
        return std::string(); // Nothing Left
    }

    std::basic_string<char>::size_type lastIndex = str.find_last_not_of(elementsToTrim);
    return str.substr(firstIndex, lastIndex - firstIndex + 1);
} // trim

// getValue()
template<>
float Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stof(str, &remainder);
} // getValue <float>

// getValue()
template<>
int Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stoi(str, &remainder);
} // getValue <int>

// getValue()
template<>
unsigned Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stoul(str, &remainder);
} // getValue <unsigned>

// convertToUnsigned()
unsigned Utility::convertToUnsigned(const std::string& str) {
    unsigned u = 0;
    if (!stringToValue(str, &u, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
        throw strStream.str();
    }
    return u;
} // convertToUnsigned

// convertToInt()
int Utility::convertToInt(const std::string& str) {
    int i = 0;
    if (!stringToValue(str, &i, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
        throw strStream.str();
    }
    return i;
} // convertToInt

// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
    float f = 0;
    if (!stringToValue(str, &f, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
        throw strStream.str();
    }
    return f;
} // convertToFloat

// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
    std::vector<std::string> vResult;
    if ( strDelimiter.empty() ) {
        vResult.push_back( strStringToSplit );
        return vResult;
    }

    std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
    while ( true ) {
        itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
        std::string strTemp( itSubStrStart, itSubStrEnd );
        if ( keepEmpty || !strTemp.empty() ) {
            vResult.push_back( strTemp );
        }

        if ( itSubStrEnd == strStringToSplit.end() ) {
            break;
        }

        itSubStrStart = itSubStrEnd + strDelimiter.size();
    }

    return vResult;

} // splitString

The includes required for this class that are found in stdafx.h are: vector, string, conio.h, and maybe tchar.h and I also use this enum for main's return values which is also found in stdafx.h stdafx.h中可以找到的该类的include包括:vector,string,conio.h,也许还有tchar.h,我也将此枚举用于main的返回值,该返回值也可以在stdafx.h找到

enum ReturnCode {
    RETURN_OK = 0,
    RETURN_ERROR = 1,
}; // ReturnCode

As for your Movie class you have defined your functions to retrieve data, but you have not shown that you have defined any setting methods nor constructors. 对于Movie类,您已经定义了用于检索数据的函数,但是尚未显示已定义任何设置方法或构造函数。 Also your getters should be declared as const functions since these functions will not change the data stored in your class object. 同样,您的getter应该声明为const函数,因为这些函数不会更改存储在您的类对象中的数据。 Your class should look as such: 您的课程应如下所示:

Movie.h 电影.h

#ifndef MOVIE_H
#define MOVIE_H

class Movie {
private:
     std::string m_strTitle;
     std::string m_strYear;
     std::string m_strGenre;
     std::string m_strLength;
     std::string m_Rating;

public:
     Movie(); // Default Constructor
     Movie( const std::string& strTitle, const std::string& strYear, const std::string& strGenre, 
            const std::string& strLength, const std::string& strRating();

    std::string getTitle() const;
    std::string getYear() const;
    std::string getGenre() const;
    std::string getLength() const;
    std::string getRating() const;

    void setTitle( const std::string& strTile );
    void setYear( const std::string& strYear );
    void setGenre( const std::string& strGenre );
    void setLength( const std::string& strLength );
    void setRating( const std::string& strRating );

private:
    Movie( const Movie& c ); // Not Implemented
    Movie& operator=( const Movie& c ); // Not Implemented             

}; // Movie

#endif // MOVIE_H

Movie.cpp 电影.cpp

#include "stdafx.h"
#include "Movie.h"

// Movie()
Movie::Movie() {
} // Movie

// Movie()
Movie::Movie( const std::string& strTitle, const std::string& strYear, const std::string& strGenre,
              const std::string& strLength, const std::string& strRating ) :
m_strTitle( strTitle ),
m_strYear( strYear ),
m_strGenre( strGenre ),
m_strLength( strLength ),
m_strRating( strRating ) {
} // Movie

// getTitle()
std::string Movie::getTitle() const {
    return m_strTitle;
} // getTitle 

// getYear()
std::string Movie::getYear() const {
    return m_strYear;
} // getYear

// getGenre()
std::string Movie::getGenre() const {
    return m_strGenre;
} // GetGenre

// getLength()
std::string Movie::getLength() const {
    return m_strLength;
} // getLength

// getRating()
std::string Movie::getRating() const {
    return m_strRating;
} // getRating

// setTitle()
void Movie::setTitle( const std::string& strTile ) {
    m_strTitle = strTile;
} // setTitle

// setYear()
void Movie::setYear( const std::string& strYear ) {
    m_strYear = strYear;
} // setYear

// setGenre()
void Movie::setGenre( const std::string& strGenre ) {
    m_strGenre = strGenre;
} // setGenre

// setLength()
void Movie::setLength( const std::string& strLength ) {
    m_strLength = strLength;
} // setLength

// setRating()
void Movie::setRating( const std::string& strRating ) {
    m_strRating = strRating;
} // setRating

Now as for parsing your string the function of use in the Utility class is Utility::splitString() You will need to go through a for loop for as many entries as there are in your array and for each pass you will have to parse that string then construct a Movie object either by using its default constructor then populating each member or by constructing the object with the appropriate constructor. 现在,解析字符串时,在Utility类中使用的功能是Utility::splitString()您将需要通过for循环,以获取数组中的所有条目,并且每次传递都必须解析该条目字符串,然后使用其默认构造函数,然后填充每个成员,或通过使用适当的构造函数构造该对象,构造一个Movie对象。 I will show you an example of how to use the splitString() function. 我将向您展示如何使用splitString()函数的示例。

main.cpp main.cpp

#include "stdafx.h"
#include "Utility.h"
#include "Movie.h" 

int main() {
    std::string test( "Hello World How Are You Today" );
    std::vector<std::string>> vResults;

    vResults = Utility::splitString( test, " " );

    Utility::pressAnyKeyToQuit();
    return RETURN_OK;
} // main

Here splitString will take as its first parameter the string that you want to parse, as its second parameter the delimiting string or char as in your case it would be the "|" 在这里,splitString将要解析的字符串作为第一个参数,将分隔字符串或char作为第二个参数作为您的情况,因为在这种情况下它将是"|" character and it will save the results into a vector of strings. 字符,它将结果保存到字符串向量中。 From here on each pass of your for loop then it is just a matter of constructing your Movie objects while assigning them the appropriate values. 从这里开始,在for循环的每一遍中,只需构造Movie对象,同时为其分配适当的值即可。

To split a string, use the find or find_first_of function from std::string to get the positions of the delimiters. 要拆分字符串,请使用std::stringfindfind_first_of函数获取分隔符的位置。 Then use substr to get the substrings between these delimiters. 然后使用substr获取这些定界符之间的子字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM