2

I have a text file containing a bunch of data which is actually a student list.
The structure is like: "Name" "Telephone" "Gender" "StudentID" "Email"

Here is a sample of the list:

Roger Pont 70778745 M 20120345 hills@school.edu
Tommy Holness 5127438973 M 20120212 tommy@school.edu
Lee Kin Fong 864564456434 F 30245678 fong@school.edu

The data is stored in a text file and I have already used the getline() function to convert each line into a string.

That is: student[0] contains "Roger Pont 7077874567 M 20120345 hills@school.edu"

My task is to sort the records according to StudentID in ascending order.

My problem is that I wanted to split the strings into different variable types.
However, since some names have more spaces in between and telephone number consists of different lengths, I can't use input and output streams is this way:
stream >> name[i] >> tel[i] >> gender[i] >> StudentID[i] >> email[i];

Any ideas how I can split the strings into different variables?

Thanks in advance.

Remarks: I have read this (Splitting a string into multiple variables in C++) but unlike that case, I don't have a specific pattern such as having the word "age" before the integer that represents age.

Community
  • 1
  • 1
user2215892
  • 37
  • 1
  • 1
  • 5
  • It looks like that phone number is right after the name? Maybe you can find the first number in the whole string, then everything before that is the name. Also, if the phone numbers are purely number, the length won't matter because it's a single string(w/o whitespace) – tianz Mar 29 '13 at 10:05
  • possible duplicate of [Splitting a string in C++](http://stackoverflow.com/questions/236129/splitting-a-string-in-c) – Bo Persson Mar 29 '13 at 10:32
  • I am *selectively* splitting a string, as the solution here http://stackoverflow.com/questions/236129/splitting-a-string-in-c would put one's name, e.g. Roger Pont into 2 strings Roger and Pont. But what I want is just one string containing Roger Pont. – user2215892 Mar 29 '13 at 10:40

2 Answers2

5
Roger Pont 70778745 M 20120345 hills@school.edu
Tommy Holness 5127438973 M 20120212 tommy@school.edu
Lee Kin Fong 864564456434 F 30245678 fong@school.edu

Looking at the above data, if we process each line backward, then the problem would become quite easy:

  • Split the words on one line. Say the number of words is N.
  • The last word is email, i.e words[N-1] => email address
  • The second last is studentid, i.e words[N-2] => student id.
  • Likewise, third last is gender, fourth last is phone, and the remaining words make the name.

That gave you enough hint.

Code:

#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iterator>
#include <cassert>

struct student
{
  std::string name;
  std::string phone;
  std::string gender;
  std::string student_id;
  std::string email;
};

int main()
{
    std::vector<student> students;

    std::string line;
    while(std::getline(std::cin, line))
    {
        std::istringstream ss(line);
        std::istream_iterator<std::string> begin(ss), end;
        std::vector<std::string> words(begin, end); 

        assert(words.size() >= 5); 

        int n = words.size() - 1;
        student s { words[0], words[n-3], words[n-2], words[n-1], words[n] };
        for (int i = 1 ; i < n - 3 ; i++) s.name += " " + words[i];

        students.push_back(s);
    }

    //printing
    for(auto && s : students)
        std::cout << "name       = " << s.name  << "\n"
                  << "phone      = " << s.phone << "\n"
                  << "gender     = " << s.gender << "\n"
                  << "student_id = " << s.student_id << "\n"
                  << "email      = " << s.email << "\n\n";
}

Input:

Roger Pont 70778745 M 20120345 hills@school.edu
Tommy Holness 5127438973 M 20120212 tommy@school.edu
Lee Kin Fong 864564456434 F 30245678 fong@school.edu

Output:

name       = Roger Pont
phone      = 70778745
gender     = M
student_id = 20120345
email      = hills@school.edu

name       = Tommy Holness
phone      = 5127438973
gender     = M
student_id = 20120212
email      = tommy@school.edu

name       = Lee Kin Fong
phone      = 864564456434
gender     = F
student_id = 30245678
email      = fong@school.edu

Online Demo

Now spend some time to understand the code. The code I showed you is written using C++11. It demonstrates many idioms of Modern C++.

  • How to read file. Line by line.
  • How to split a line, and populate a vector of strings.
  • How to fill the struct (problem specific)

Hope that helps.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Thanks! A feasible way in solving the problem. Since I am not so familar with C++, is there actually ways I can cin from the end but not from the start? Or I must use a for loop to loop through the characters in order to go backward? – user2215892 Mar 29 '13 at 10:29
  • 2
    Fabulous! Thank you very much! A very complete and comprehensive solution! – user2215892 Mar 29 '13 at 10:49
0
#include <iostream>
#include <vector>
#include <sstream>

using namespace std;

    std::vector<std::string> strings;
    std::istringstream f("Roger Pont 70778745 M  20120345 hills@school.edus");
    std::string s;
    while (std::getline(f, s, ' ')) {
        std::cout << s << std::endl;
        strings.push_back(s);
    }

This have a problem with spacing between two words is greater than 1 space ' '.

Blood-HaZaRd
  • 2,049
  • 2
  • 20
  • 43
  • The problem is that some names is longer and with more spaces. This solution split name into two strings but I just want one. – user2215892 Mar 29 '13 at 10:23
  • yes that's right, I thought you want to split the line using space pattern. in this case the solutikn given by Nawaz is right, as the first part, which contains the name, may be complex. – Blood-HaZaRd Mar 29 '13 at 10:30