1

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,

Tai Chau
  • 35
  • 1
  • 9
  • 1
    https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong and consider that lines of text are not terminated with a comma. –  May 05 '18 at 19:59
  • You don't need `tenfile.c_str()` for printing. `cout << ` works with C++ strings. – Kostas May 05 '18 at 20:06

3 Answers3

2

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

Dmich
  • 120
  • 6
0

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
  • I would like to ask that if my values in test.txt file greater than 10. Could I use isdigit() to print the correct values ? – Tai Chau May 06 '18 at 11:51
  • @TaiChau since we're reading char by char it will detect as 10 as 1 and 0. Will print data: 1 data: 0 instead. Do you want an alternative solution for this problem? I can write. – Tuğberk Kaan Duman May 06 '18 at 11:53
  • Yes. Please give me a solution for value over 10. I would like to print the values over 10 or large number like this: **10 -> data: 10** or **192 -> data: 192**. Thanks – Tai Chau May 06 '18 at 12:00
  • @TaiChau I've finished it, updating my answer now. – Tuğberk Kaan Duman May 06 '18 at 12:52
  • Thank you so much for your solution. But could you explain about this statement? I do not really understand it. else if (in_spaces) { num_words++; in_spaces = false; }. Why in_spaces=false ? – Tai Chau May 06 '18 at 13:33
  • @TaiChau to count word amount I've actually counted space count since words are basically spaces in between. I've checked if the character is a space and if it's a space increased word number by 1 and turned space to off because I want to check next one again. Think it like resetting the state. – Tuğberk Kaan Duman May 06 '18 at 13:52
0

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();
}
Eljay
  • 3,156
  • 2
  • 12
  • 21