c ++:将文本文件解析并读取到由分隔符

时间:2016-02-15 19:39:21

标签: c++ arrays

大家下午好,

首先,感谢您花时间输入并帮助我理解我的问题。我将透露这是一个分配问题,所以我想理解它,而不是给出完整的代码。

根据问题的标题,我正在尝试为我的作业设计一个程序。我已经包含了以下信息。

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.

这是我到目前为止所拥有的:

#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;
}

到目前为止,我的输出是:

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 

因此,您可以看到我已将数据放入一个数组中。现在我正在努力做到这一点。我希望能够解析这些数据并将其提供给我的DVD类。特别是我的问题概述我希望能够将所有电影名称放在一个数组中,将日期放在另一个数组中等等,直到每个数据集都匹配。一旦完成,我希望能够提示用户选择一个选项从那里就有相应的功能发生。

我还为我的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://这些是这个类的成员。他们将存储我们所需的所有信息     string moviename;     弦年;     弦乐流派;     串时间;     字符串评级;
};

这是我的代码的另一部分。我把它放在这里,因为人们需要看看我是否尝试过

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
}

2 个答案:

答案 0 :(得分:1)

您已成功读取文本文件中的数据并填充了字符串数组。现在你需要做的是编写一个解析函数来解析数组中的每个字符串或行。然后在解析每一行时,您需要将每个内容保存到您的班级中。

我可以为你提供一个泛型函数,只要你使用相同的分隔符就会为你解析字符串;它作为静态方法封装在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

#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

stdafx.h中找到的此类所需的包含:vector,string,conio.h和tchar.h,我也将此枚举用于主要的返回值,这也是在stdafx.h

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

至于你的Movie类,你已经定义了检索数据的函数,但是你没有证明你已经定义了任何设置方法和构造函数。此外,您的getter应声明为const函数,因为这些函数不会更改存储在类对象中的数据。你的班级应该是这样的:

<强> 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

现在,对于解析你的字符串,在Utility类中使用的函数是Utility::splitString()你将需要通过for循环来获取与数组中一样多的条目,并且每次传递都需要解析该字符串然后通过使用其默认构造函数然后填充每个成员或通过使用适当的构造函数构造对象来构造Movie对象。我将向您展示如何使用splitString()函数。

<强>的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

这里splitString将第一个参数作为你要解析的字符串,因为它的第二个参数是分隔字符串或char,就像你的情况一样,它将是"|"字符,它会将结果保存到矢量的字符串。从你的for循环的每次传递开始,只需构建Movie个对象,同时为它们分配适当的值。

答案 1 :(得分:0)

要拆分字符串,请使用find中的find_first_ofstd::string函数来获取分隔符的位置。然后使用substr获取这些分隔符之间的子字符串。