C ++逐行读取文件,有些行的列数与其他行不同

时间:2016-03-05 22:01:41

标签: c++ multiple-columns readfile skip

我的text.txt看起来像这样:

1   52  Hayden Smith        18:16   15  M   Berlin
2   54  Mark Puleo          18:25   15  M   Berlin
3   97  Peter Warrington    18:26   29  M   New haven
4   305 Matt Kasprzak       18:53   33  M   Falls Church
5   272 Kevin Solar         19:17   16  M   Sterling
6   394 Daniel Sullivan     19:35   26  M   Sterling
7   42  Kevan DuPont        19:58   18  M   Boylston
8   306 Chris Goethert      20:00   43  M   Falls Church

问题是,对于第三行,城镇的名称是纽黑文,新的和避风港之间有一个空间。而对于第四行,瀑布和教堂之间还有一个空间。当我逐行读取文件时,这会产生问题。

所以,我的代码看起来像这样:

ifstream infile("text.txt", ios::in);
if(!infile)
{
    cerr<<"File could not be opend"<<endl;
}

SortedLinked mylist;

int a;
int b;
string c;
string d;             // I have eight different variables, representing
string e;             // each column, but some lines have nine columns.
int f;                   
char g;
string h;

string mystr;
int mymin;
int mysec;

while(infile>>a>>b>>c>>d>>e>>f>>g>>h)
{

   // This does not work, because as you get to line three, h is New, there
   // is no variable to store Haven. Therefore my code can only get to line 
   // 3. 

    mystr = c+d;
    mymin = convertString<int>(e.substr(0,2));
    mysec = convertString<int>(e.substr(3, 4));


    Runner M(mystr, f, mymin, mysec);
    //M.print();
    mylist.additem(M);


}

另外,如果您尝试执行以下操作:

replace(h.begin(), h.end(), ' ', '_')

尝试填补New和haven之间的下划线,它将无法正常工作。 因为这个尝试用另一个替换变量,h在这里是新的,它不是新的避风港,你不能到达避风港,因为避风港是另一个变量。因此,您无法用下划线替换空格。

另外,如果您尝试执行以下操作:

while(infile>>a>>b>>c>>d>>e>>f>>g>>h>>i)

这也行不通,因为当你到达第1行时,只有正确的列,没有什么可以存储到变量i中。像这样的代码只能让你到第1行。

如果您有其他方法可以执行此操作,例如跳过城镇名称列,第8列和第9列(对于某些行),因为我甚至不需要城镇的名称。

或者,你可以摆脱新天堂和秋天教堂之间的空间。任何事情都会受到赞赏。

4 个答案:

答案 0 :(得分:4)

您可以使用getline阅读其余部分。

while( (infile>>a>>b>>c>>d>>e>>f>>g) && getline(infile, h))

答案 1 :(得分:2)

您应该考虑使用getline。这样你就可以逐行阅读,然后解析输入。

一旦你将这一行读入一个字符串,你就可以像往常一样解析它,将每个子字符串拆分为一个空格,直到你得到该城镇的名称,其中你只需将子字符串从那里拆分为行结束到你的城镇名称变量。

答案 2 :(得分:1)

您可以使用一个小技巧:因为您希望忽略的空格仅出现在最后一个条目上,您可以使用std::getline而不是>>来读取该城镇的名称。

string str;
while (getline(infile, str)) { // Read the entire line
    stringstream ss(str);
    ss>>a>>b>>c>>d>>e>>f>>g;
    getline(ss, h);
    ... // The rest of your code
}

答案 3 :(得分:0)

我已经有一个现有的Utility类来处理字符串,在使用你的文件结构一段时间之后,这就是我能想到的。但是,我确实需要修改现有的文本文件才能使其正常工作。您的所有列都必须有一个空格(可以更改为单个选项卡),对于最后一个城镇名称有两个单词的条目,我用双引号将它们封装起来。所以现在你的text.txt文件看起来像这样:

<强>的text.txt

1 52 Hayden Smith 18:16 15 M Berlin
2 54 Mark Puleo 18:25 15 M Berlin
3 97 Peter Warrington 18:26 29 M "New Haven"
4 305 Matt Kasprzak 18:53 33 M "Falls Church"
5 272 Kevin Solar 19:17 16 M Sterling
6 394 Daniel Sullivan 19:35 26 M Sterling
7 42 Kevan DuPont 19:58 18 M Boylston
8 306 Chris Goethert 20:00 43 M "Falls Church"

这是工作计划。

<强> stdafx.h中

#ifndef STDAFX_H
#define STDAFX_H

#include <stdio.h>
#include <tchar.h>
#include <conio.h>

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

#include <algorithm>

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

#endif // STDAFX_H

<强> stdafx.cpp

#include "stdafx.h"

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

<强>的main.cpp

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

struct Data {
    int a;
    int b;
    std::string c;
    std::string d;
    std::string e;
    int f;
    char g;
    std::string h;
};

int main() {
    std::string strFilename( "text.txt" );
    std::ifstream file; 

    std::string strLine;
    std::vector<std::string> vTemp;
    std::vector<std::string> vResult;

    std::vector<Data> vData;

    // Open File For Reading
    file.open( strFilename.c_str() );
    // Check For Error Of Opening File
    if ( !file.is_open() ) {
        std::cout << "Error opening file (" << strFilename << ")" << std::endl;
        return RETURN_ERROR;
    }

    // Continue Until End Of File
    while( !file.eof() ) {
        // Get Single Full Line Save To String
        std::getline( file, strLine );

        // Split String Using A Double Quote Delimiter
        vTemp = Utility::splitString( strLine, "\"" );

        // Check To See If vTemp Has More Than One String
        if ( vTemp.size() > 1 ) {
            // Store The Last Value Of vResult - 
            // We Need To Use Pop Back To Account For Last Double Quote
            vTemp.pop_back(); // Remove Last Double Quote
            std::string temp = vTemp.back(); 
            vTemp.pop_back(); // Remove Wanted String From vTemp.

            // At This Point We Need To Parse vTemp Again Using Space Delimiter
            vResult = Utility::splitString( vTemp[0], " " );

            // Need To Account For Last Space In Vector
            vResult.pop_back();

            // Now We Can Push Our Last String Back Into vResult
            vResult.push_back( temp );          

        } else if ( vTemp.size() == 1 ) {
            // Just Parse vTemp Using Space Delimiter
            vResult = Utility::splitString( vTemp[0], " " );
        }


        // Print Out Results For Validity
        for ( unsigned u = 0; u < vResult.size(); u++) {
            std::cout << vResult.at(u) << " ";
        }
        std::cout << std::endl;

        // Here Is Where You Would Populate Your Variables, Structures Or Classes On Each Pass Of The While Loop.
        // With This Structure There Should Only Be 8 Entries Into Our vResult
        Data temp;
        temp.a = Utility::convertToInt( vResult[0] );
        temp.b = Utility::convertToInt( vResult[1] );
        temp.c = vResult[2];
        temp.d = vResult[3];
        temp.e = vResult[4];
        temp.f = Utility::convertToInt( vResult[5] );
        temp.g = vResult[6].at( 0 ); // Should Only Be One Character In This String
        temp.h = vResult[7];

        vData.push_back( temp );
    }

    std::cout << std::endl << std::endl;

    // Print Using Structure For Validity
    std::cout << "---------------------------------------\n";
    for ( unsigned u = 0; u < vData.size(); u++ ) {
        std::cout << vData[u].a << " " 
                  << vData[u].b << " "
                  << vData[u].c << " "
                  << vData[u].d << " "
                  << vData[u].e << " "
                  << vData[u].f << " "
                  << vData[u].g << " "
                  << vData[u].h << std::endl;
    }


    // Close File
    file.close();

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

据我所知,这是一个完整的工作程序,该程序已成功编译并构建在使用MSVS 2015 Community Edition的运行Windows 7 64bit和8GB Ram的Intel四核3.0Ghz上。没有编译或构建错误,并且预期数据正确打印到控制台窗口。