0

I am writing a program which is suppose to be able to open a file, read each line in and separate a LAST NAME, First name: 3 test scores. the format of the file being read is Mark Titan: 80 80 85. I am suppose to output TITAN, Mark: 80 80 85. We are using strings, and so far using my teachers code i have gotten the file to separate completely. it would show the test scores in order from 1-100(100 comes first because it starts with 1 but i can fix that after) and then alphabetically the names. I need help creating a substr of the line, creating a string of just the full name and splitting that into first and last and then sort them correctly. I have been messing with .find but im not sure how to split this vector into smaller vectors. please help and thank you.

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

    using namespace std;
    void openFile(ifstream &in);
    void processFile(ifstream &in, vector<string> &list);
    void display(const vector<string> &list);
    void sort(vector<string> &list);

    int main(int argc, char *argv[])
    {
        ifstream in;
        string line;
        vector<string> words;
        openFile(in);
        processFile(in, words);
        display(words);
        return 0;
    }


    void openFile(ifstream &in)
    {
        string fileName;
        bool again;
        do
        {
            again = false;
            cout<<"What is the name of the file to you wish to sort? (.txt will be added if no extension is included): ";
            cin>>fileName;
            if(fileName.find('.') >= fileName.size() )
                fileName +=  ".txt";
            in.open(fileName.c_str());
            if(in.fail())
            {
                in.close();
                in.clear();
                again = true;
                cout<<"That file does not exist! Please re-enter"<<endl;
            }
        }while(again);
    }

    void processFile(ifstream &in, vector<string> &list)
    {
        string line, word;
        int s1,s2,s3;
        stringstream ss;
        while(getline(in, line, ':'))
        {
            ss<<line.substr(line.find(' ') + 1);
            while(ss>>word)
                list.push_back(word);
            ss.clear();
        }
        sort(list);
    }

    void sort(vector<string> &list)
    {
        for(unsigned int i =  0; i < list.size(); ++i)
            for(unsigned int j = 0; j < list.size(); ++j)
                if(list[i] < list[j])
                {
                    string temp = list[i];
                    list[i] = list[j];
                    list[j] = temp;
                }
    }

    void display(const vector<string> &list)
    {
        cout<<"The file read had "<<list.size()<<" words in it"
            <<endl<<"In sorted order, they are:"<<endl;
        for(unsigned int i = 0; i < list.size();++i)
            cout<<list[i]<<endl;}

2 Answers2

0

You can Tokenize the line twice. First, split on the colon, then split the first token on the space. Also, your teacher will throw empty and malformed lines at you. For instance missing colon or missing name (or missing first/last name). Handle those errors by counting the tokens returned when you split a string or sub string.

void Tokenize(const std::string& theSourceString, std::vector<std::string>& theTokens, const std::string& theDelimiter)
{
    // If no delimiter is passed, tokenize on all white space.
    if (theDelimiter.empty())
    {
        std::string aBuffer; // Have a buffer string
        std::stringstream ss(theSourceString); // Insert the string into a stream

        while (ss >> aBuffer)
        {
            theTokens.push_back(aBuffer);
        }
        return; //?
    }

    // Skip delimiters at beginning.
    std::string::size_type aLastPosition = theSourceString.find_first_not_of(theDelimiter, 0);

    // Find first "non-delimiter".
    std::string::size_type aPosition = theSourceString.find_first_of(theDelimiter, aLastPosition);

    while (aPosition != std::string::npos || aLastPosition != std::string::npos)
    {
        // Found a token, add it to the vector.
        theTokens.push_back(theSourceString.substr(aLastPosition, aPosition - aLastPosition));

        // Skip delimiters.  Note the "not_of"
        aLastPosition = theSourceString.find_first_not_of(theDelimiter, aPosition);

        // Find next "non-delimiter"
        aPosition = theSourceString.find_first_of(theDelimiter, aLastPosition);
    }
}

Example use:

std::vector<std::string> tokens;
Tokenize("{ 1, 2, 3, 4, 5 }", tokens, "{}, " );
James Poag
  • 2,320
  • 1
  • 13
  • 20
0

I have this Utility class that has a bunch of methods for string manipulation. I will show the class function for splitting strings with a delimiter. This class has private constructor so you can not create an instance of this class. All the methods are static methods.

Utility.h

#ifndef UTILITY_H
#define UTILITY_h

// Library Includes Here: vector, string etc.

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

private:
    Utility();
};

Utility.cpp

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

Main.cpp -- Usage

#include <string>
#include <vector>
#include "Utility.h"

int main() {
    std::string myString( "Hello World How Are You Today" );

    std::vector<std::string> vStrings = Utility::splitString( myString, " " );

    // Check Vector Of Strings
    for ( unsigned n = 0; n < vStrings.size(); ++n ) {
        std::cout << vStrings[n] << " ";
    }
    std::cout << std::endl;

    // The Delimiter is also not restricted to just a single character
    std::string myString2( "Hello, World, How, Are, You, Today" );

    // Clear Out Vector
    vStrings.clear();

    vStrings = Utility::splitString( myString2, ", " ); // Delimiter = Comma & Space

    // Test Vector Again
    for ( unsigned n = 0; n < vStrings.size(); ++n ) {
        std::cout << vStrings[n] << " ";
    }
    std::cout << std::endl;

    return 0;
}
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59