13
\$\begingroup\$

I have a text file that contains name, age, salary, hoursWorked, randomText and are filled with different delimiters.

Text file:

susan:25-2600,28[asd]
mary:21-2200,38[asd]
john:23-3400,46[asd]

Instead of breaking them into individual strings using the code shown below:

string name,age,salary,hoursWorked,randomText;
ifstream readFile("textfile.txt");
while(getline(readFile,line)) {
 stringstream iss(line);
 getline(iss, name, ':');
 getline(iss, age, '-');
 getline(iss, salary, ',');
 getline(iss, hoursWorked, '[');
 getline(iss, randomText, ']');
}
readFile.close();

What are some better strategies other than coding it this way?

Side note

I declared all the variables to strings because of the getline() method.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 9, 2014 at 5:58
\$\endgroup\$

1 Answer 1

15
\$\begingroup\$

I would create a class and define an input operator:

struct Person
{
 std::string name;
 std::string age;
 std::string salary;
 std::string hoursWorked;
 std::string randomText;
 friend std::istream& operator>>(std::istream& str, Person& data)
 {
 std::string line;
 Person tmp;
 if (std::getline(str,line))
 {
 std::stringstream iss(line);
 if ( std::getline(iss, tmp.name, ':') && 
 std::getline(iss, tmp.age, '-') &&
 std::getline(iss, tmp.salary, ',') &&
 std::getline(iss, tmp.hoursWorked, '[') &&
 std::getline(iss, tmp.randomText, ']'))
 {
 /* OK: All read operations worked */
 data.swap(tmp); // C++03 as this answer was written a long time ago.
 }
 else
 {
 // One operation failed.
 // So set the state on the main stream
 // to indicate failure.
 str.setstate(std::ios::failbit);
 }
 }
 return str;
 }
 void swap(Person& other) throws() // C++03 as this answer was written a long time ago.
 {
 swap(name, other.name);
 swap(age, other.age);
 swap(salary, other.salary);
 swap(hoursWorked, other.hoursWorked);
 swap(randomText, other.randomText)
 }
};

Now your code looks like this:

Person data;
while(readFile >> data)
{
 // Do Stuff
}

PS. I noticed you were using string and ifstream without the std::. This suggests you have using namespace std; in your code. Please don't do that. see Why is "using namespace std;" considered bad practice?

Don't explictly close() a file unless you are going to check that it worked (or are going the re-open). Prefer to let the destructor do the closing (that way it is exception safe). See: My C++ code involving an fstream failed review

answered Jan 10, 2014 at 0:31
\$\endgroup\$
3
  • \$\begingroup\$ In the operator>> definition I needed to add the class before the member variables (e.g. data.name, data.age) in the getline calls for this to compile. \$\endgroup\$ Commented Mar 26, 2014 at 12:37
  • \$\begingroup\$ @user39469: Sorry. Fixed. \$\endgroup\$ Commented Mar 26, 2014 at 14:45
  • \$\begingroup\$ Nice. The only thing I would change: I would use a local Person tmp; instance, and in the if code block (the "OK: All read operations worked" part) I would write data = std::move(tmp); (or std::swap(data, tmp);).. This way, you avoid the case when the stream doesn't actually contain a valid person (in that case, if one of the getline calls fails, data will not be partially filled with garbage). \$\endgroup\$ Commented Mar 26, 2014 at 15:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.