Processing lines from one text file to another

2019-01-29 07:58发布

问题:

I would like to give thanks to everyone who helped me with my problem. I was finally able to arrange the data by birth year! Very much appreciated. If anyone can help me with this final question, that'd be great

If I have lines in a text file that look like this:

1    4:48:08   Orvar Steingrimsson                 1979   30 - 39 ara      IS200 
2    4:52:25   Gudni Pall Palsson                  1987   18 - 29 ara      IS870 

How can I output this data onto a new text file but only listing three things: year - name - time ... so that these two lines would look like this:

1979   Orvar Steingrimsson   4:48:08
1987   Gudni Pall Palsson    4:52:25

My guess was this:

ifstream in("inputfile.txt");
ofstream out("outputfile.txt");
int score, year;
string name, time, group, team;
while (getline(in,str));
in >> score >> time >> name >> year >> group >> team;
//and then do something like this
out << year << name << time << '\n';

However I have a feeling I won't be able to loop this through the whole text file and all 200 lines. Any tips appreciated! Thanks

回答1:

"I know that the year is always the 54th to 58th character in each line"

So, consider this :

int main ()
{
    ifstream  in("laugavegurinn.txt", ios::in);
    ofstream out("laugavegurinn2.txt");
    string str;
    multimap<int, string> datayear;

    while (getline(in,str)) {
         int year = stoi(str.substr(54, 4));
         datayear.insert(make_pair(year,str)); //use insert function
         // multimap don't have [] operator
           }

    for (auto v : datayear) 
        out << v.second << "\n";

    in.close();
    out.close();
}


回答2:

For starters, read the lines into an std::vector<std::string>, using std::getline. Then sort them in the desired order. Then output them. So main becomes basically three lines:

std::vector<Line> data( readLines( inFile ) );
sortByBirthYear( data );
std::copy( data.begin(), data.end(), std::ostream_iterator<std::string>( outFile, "\n" ) );

Of course, readLines and sortByBirth need to be written as well, but they're both fairly trivial as well.

Alternatively, and probably better, you could define a DataLine class with an operator>>, and operator<< and a comparison function (operator<), and then all you'd need is:

std::vector<DataLine> data(
    (std::istream_iterator<DataLine>( inFile )),
    (std::istream_iterator<DataLine>()) );
std::sort( data.begin(), data.end() );
std::copy( data.begin(),
           data.end(),
           std::ostream_iterator<std::string>( outFile, "\n" ) );

That's what I'd do, but if you've just started C++, you may not have covered the necessary basics yet, like classes and operator overloading.

One thing I'd also add, based on your code: don't ever access data you've input without first checking that the input succeeded.

EDIT (implementation using just the basic functionality):

As above (but without the Line type):

std::vector<std::string> data( readLines( inFile ) );
std::sort( data.begin(), data.end(), orderByBirthYear );
std::copy( data.begin(), data.end(),
           std::ostream_iterator<std::string>( outFile, "\n" ) );

with:

std::vector<std::string>
readLines( std::istream& source )
{
    std::vector<std::string> results;
    std::string line;
    while ( std::getline( source, line ) ) {
        results.push_back( line );
    }
    return results;
}

bool
orderByBirthYear( std::string const& lhs, std::string const& rhs )
{
    return lhs.compare( 54, 4, rhs, 54, 4 ) < 0;
}

But I insist: this is not how one should solve it. Any reasonable solution would start by defining a class for your data, and define all of the operations using this. This means not just defining a class, but also operator overloading; if you've just started, you likely haven't seen any of these yet (and the assignment is not a good sign with regards to the quality of the course).

For the rest, you're on the right track; for line oriented input, you should read using getline. After that, however, the line has been extracted from the input; to parse it further, you need to initialize an std::istringstream with it, and read from that. Except that your input format seems to be based on columns, so you'd probably use the substr function of std::string to get the individual fields. Once you've got them, you'll want to strip leading and trailing white space, and maybe convert to numeric types (although for just sorting by year, this is not necessary). But all of this would logically occur in a user defined operator>> to a Data class. (Similarly, you'd provide a user defined operator<< to write the sorted data out. And typically, orderByBirthYear, above, would be a class as well.)