简体   繁体   中英

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

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. They will store all the information we need for this class string 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.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

#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

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. Also your getters should be declared as const functions since these functions will not change the data stored in your class object. Your class should look as such:

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

#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. I will show you an example of how to use the splitString() function.

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

To split a string, use the find or find_first_of function from std::string to get the positions of the delimiters. Then use substr to get the substrings between these delimiters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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