Tai Chau
Tai Chau

Reputation: 33

Cout the getline command for txt file

I am a newbie in programming by C++ language. I am trying to read a text file (.txt file) by C++ language.

My text file's name being test.txt has the contest as below:

1,3,5,7,9,8,1,2,3
0,2,4,6,8,8,1,2,3
1,3,5,7,9,8,1,2,3
0,2,4,6,8,8,1,2,3

I wote a code as below to read test.txt:

#include<stdio.h>
#include<iostream>
#include<string>
#include<sstream>
#include<stdlib.h> // atoi -> Convert string to int number
#include<fstream> // need for read file
using namespace std;
int main(){
  string tenfile;
  cout<<"Ten file: ";
  cin >> tenfile;
  cout<<tenfile.c_str()<<endl;
  int i,j;    
  int value;
  string data; // declare data in file
  ifstream myfile (tenfile.c_str());
  while(myfile.good())
    {
      getline(myfile,data,','); // use ' ' not " "
      cout << "data: " << data << endl;
    }
myfile.close();
return 0;
}

When I run this code to read test.txt, I see on the screen as below:

Ten file: test.txt
test.txt
data: 1
data: 3
data: 5
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
0
data: 2
data: 4
data: 6
data: 8
data: 8
data: 1
data: 2
data: 3
1
data: 3
data: 5    
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
...

When I saw screened values, I recognized that the first values of line 2, line 3 and line 4 does not have data: . I only saw that 0,1,0.

How can I solve this problem ? I would like to solve this problem in my C++ code and don't want to modify the test.txt file.

Thanks,

Upvotes: 1

Views: 119

Answers (3)

Tuğberk Kaan Duman
Tuğberk Kaan Duman

Reputation: 950

I've added a library for isdigit function and changed the way that you're reading the file. You can find my code explanations where the comment starts with <<------

#include<stdio.h>
#include<iostream>
#include<string>
#include<sstream>
#include<stdlib.h> // atoi -> Convert string to int number
#include<fstream> // need for read file
#include<cctype> // <<------ Included this for isdigit
using namespace std;

int main() {
    string tenfile;
    cout << "Ten file: ";
    cin >> tenfile;
    cout << tenfile << endl; // <<------ Removed .c_str() you don't need it
    int i, j;
    int value;

    ifstream myfile(tenfile); // <<------ Removed .c_str() you don't need it
    char c;
    while (myfile.get(c)) // <<------ Reading file char by char
    {
        //getline(myfile, data, ','); // use ' ' not " "
        if (isdigit(c)) // <<------ If char is a digit
            cout << "data: " << c << endl; // <<------ Print that char
    }
    myfile.close();
    return 0;
}

This was the result of the code above:

data: 1
data: 3
data: 5
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
data: 0
data: 2
data: 4
data: 6
data: 8
data: 8
data: 1
data: 2
data: 3
data: 1
data: 3
data: 5
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
data: 0
data: 2
data: 4
data: 6
data: 8
data: 8
data: 1
data: 2
data: 3

If you don't want to add a new library just for isdigit function, you can write it yourself. Basically this:

int check_digit (char c) {
    if ((c>='0') && (c<='9'))
        return 1;
    return 0;
}

Afterwards you can do check_digit(c) instead of isdigit(c) and you can remove #include<cctype>.


Version which can read any number of size:

#include<iostream>
#include<string>
#include<fstream> // need for read file
#include <locale>
using namespace std;

int count_words(const char*);

int main() {
    string tenfile;
    cout << "Ten file: ";
    cin >> tenfile;
    cout << tenfile << endl; // <<------ Removed .c_str() you don't need it

    ifstream myfile(tenfile); // <<------ Removed .c_str() you don't need it

    unsigned int i;
    string full_text;
    getline(myfile, full_text, static_cast<char>(myfile.eof()));

    for (i = 0; i < full_text.size(); i++)
    {
        if (full_text[i] == '\n')
            full_text[i] = ' ';
        if (full_text[i] == ',')
            full_text[i] = ' ';
    }

    const unsigned int word_count = count_words(full_text.c_str());

    unsigned int k = 0;
    string display_text;
    for (i = 0; i < word_count; i++)
    {
        while (full_text[k] != ' ')
        {
            display_text += full_text[k];
            k++;
            if(k > full_text.size())
            {
                k = full_text.size();
                break;
            }
        }

        if (full_text[k] == ' ')
            k++;

        cout << "data: " << display_text << "\n";
        display_text.clear();
    }

    myfile.close();
    return 0;
}

int count_words(const char* str)
{
   bool in_spaces = true;
   int num_words = 0;

   while (*str != NULL)
   {
      if (*str == ' ')
      {
         in_spaces = true;
      }
      else if (in_spaces)
      {
         num_words++;
         in_spaces = false;
      }

      ++str;
   }

   return num_words;
}

Input file:

10,3,5,7,9,8,1,2,3
0,2,4,6,198,8,1,2,3
1,3,5,7,9,8,1,2,3
0,2,4,6,8,8,1,2,3000

Output:

Ten file: binStr.txt
binStr.txt
data: 10
data: 3
data: 5
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
data: 0
data: 2
data: 4
data: 6
data: 198
data: 8
data: 1
data: 2
data: 3
data: 1
data: 3
data: 5
data: 7
data: 9
data: 8
data: 1
data: 2
data: 3
data: 0
data: 2
data: 4
data: 6
data: 8
data: 8
data: 1
data: 2
data: 3000

Upvotes: 0

Eljay
Eljay

Reputation: 5321

I'd make these changes:

  • use the std symbols explicitly
  • read line-by-line for the outer read
  • read datum-by-datum for the inner read
  • cull out unneeded #include
  • remove dead variables
  • turn on all compiler warnings, and address them
  • use auto (since I'm in the "almost always use auto" camp)

So my version of the code looks like this:

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

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::ifstream;
using std::istringstream;
using std::string;

int main()
{
  auto tenfile = string{};
  cout << "Ten file: ";
  getline(cin, tenfile);
  cout << tenfile << endl;
  auto myfile = ifstream{tenfile};
  auto line = string{};

  while (getline(myfile, line))
  {
    auto myline = istringstream(line);
    auto data = string{};

    while (getline(myline, data, ','))
    {
      cout << "data: " << data << endl;
    }
  }

  myfile.close();
}

Upvotes: 0

Dmich
Dmich

Reputation: 130

The input is separated by commas ',' and not by new lines characters in getline(myfile,data,',');. So when you reach the end of a line in the text file, the next sequence of characters the getline function sees until the next comma is "3\n0" where '\n' is a new line character.

Then, your program prints the "3\n0" which outputs as:

data: 3
0

Your program is still printing the output.

A simple solution would be make sure that every end of line in the text file is replaced with a comma so that all values are on one line.

Another solution would be to check to see if your data contains a newline character, and split the string based on the newline character's position.

You might also change the program to read in the whole line and then split or tokenize the data by the comma character.

More on string tokenization here:
Multiple methods of string tokenizing
Tokenizing a string with strstream

Upvotes: 2

Related Questions