read text file into matrix

Hi everybody.

I'm interested in C++ programming, so I just started learning it. I already worked with structured programming, e.g. Pascal or Fortran, so I have no problems with while, for, pointers and so on. Above all I'm interested in object-oriented programming, but I'm an absolute beginner in that. I'd like to write a little programm for work in such way, but I'm very confused. I have a definite aim and I searched for tutorials or examples about it but there's a lot of different libraries and different codes (often a mix of C and C++). Can you help me with a simple and basic code, so I can learn through it?
This is the question. I want to read a text file and manipulate it to obtain a different one. The structure of the file is a matrix with 3 columns and an unknown amount of rows (cartesian coordinates). Rows are grouped and empty lines split them. I have to copy the text file into a matrix, add a fourth 'flag' column and delete the empty lines. The flag consists in a integer: it's 1 for rows following an empty line and 0 for the other rows. The flag is 9 for the last row. An example:

-8.25000 0.00000 5.00000
-8.25000 2.40000 5.00000
-8.25000 3.14041 5.02089
-8.25000 3.88838 5.09037
-8.25000 4.26046 5.14651
-8.25000 4.62873 5.21863
-8.25000 4.99130 5.30800
-8.25000 5.34627 5.41589
-8.25000 5.69174 5.54358
-8.25000 6.02580 5.69235
-8.25000 6.34657 5.86347
-8.25000 6.65214 6.05822
-8.25000 6.94062 6.27787
-8.25000 7.21010 6.52370
-8.25000 7.45869 6.79699
-8.25000 7.68448 7.09900
-8.25000 7.68448 13.00000

-6.91500 0.00000 4.86198
-6.91500 0.53300 4.86107
-6.91500 1.52750 4.84723
-6.91500 2.52103 4.85241
-6.91500 3.24041 4.90173
-6.91500 3.95730 5.00000
-6.91500 4.65508 5.14855
-6.91500 5.33864 5.35470
-6.91500 5.67153 5.48129
-6.91500 5.99659 5.62458
-6.91500 6.31240 5.78533
-6.91500 6.61753 5.96431
-6.91500 6.67352 6.00000
-6.91500 7.01575 6.23832
-6.91500 7.34042 6.50144
-6.91500 7.64348 6.78862
-6.91500 7.92086 7.09914
-6.91500 7.92086 9.00000
-6.91500 7.92086 13.00000

0.00000 0.00000 3.97457
0.00000 0.73587 3.97467
0.00000 1.77104 4.00000
0.00000 2.45523 4.02717
0.00000 3.13497 4.09151
0.00000 3.47509 4.15067
0.00000 3.81199 4.22868
0.00000 4.14536 4.32388
0.00000 4.47487 4.43462
0.00000 5.12109 4.69613
0.00000 5.74813 5.00000
0.00000 6.32759 5.31955
0.00000 6.88956 5.66551
0.00000 7.38561 6.00000
0.00000 8.12791 6.53821
0.00000 8.85263 7.09970
0.00000 8.85263 9.00000
0.00000 8.85263 13.00000

is transformed into:

-8.25000 0.00000 5.00000 1
-8.25000 2.40000 5.00000 0
-8.25000 3.14041 5.02089 0
-8.25000 3.88838 5.09037 0
-8.25000 4.26046 5.14651 0
-8.25000 4.62873 5.21863 0
-8.25000 4.99130 5.30800 0
-8.25000 5.34627 5.41589 0
-8.25000 5.69174 5.54358 0
-8.25000 6.02580 5.69235 0
-8.25000 6.34657 5.86347 0
-8.25000 6.65214 6.05822 0
-8.25000 6.94062 6.27787 0
-8.25000 7.21010 6.52370 0
-8.25000 7.45869 6.79699 0
-8.25000 7.68448 7.09900 0
-8.25000 7.68448 13.00000 0
-6.91500 0.00000 4.86198 1
-6.91500 0.53300 4.86107 0
-6.91500 1.52750 4.84723 0
-6.91500 2.52103 4.85241 0
-6.91500 3.24041 4.90173 0
-6.91500 3.95730 5.00000 0
-6.91500 4.65508 5.14855 0
-6.91500 5.33864 5.35470 0
-6.91500 5.67153 5.48129 0
-6.91500 5.99659 5.62458 0
-6.91500 6.31240 5.78533 0
-6.91500 6.61753 5.96431 0
-6.91500 6.67352 6.00000 0
-6.91500 7.01575 6.23832 0
-6.91500 7.34042 6.50144 0
-6.91500 7.64348 6.78862 0
-6.91500 7.92086 7.09914 0
-6.91500 7.92086 9.00000 0
-6.91500 7.92086 13.00000 0
0.00000 0.00000 3.97457 1
0.00000 0.73587 3.97467 0
0.00000 1.77104 4.00000 0
0.00000 2.45523 4.02717 0
0.00000 3.13497 4.09151 0
0.00000 3.47509 4.15067 0
0.00000 3.81199 4.22868 0
0.00000 4.14536 4.32388 0
0.00000 4.47487 4.43462 0
0.00000 5.12109 4.69613 0
0.00000 5.74813 5.00000 0
0.00000 6.32759 5.31955 0
0.00000 6.88956 5.66551 0
0.00000 7.38561 6.00000 0
0.00000 8.12791 6.53821 0
0.00000 8.85263 7.09970 0
0.00000 8.85263 9.00000 0
0.00000 8.85263 13.00000 9

I started to write pieces of codes but, as I wrote above, I'm very confused with libraries, classes and so on. I rely on your patience and your help, I guess it's a very simple question for a C++ expert. I need this code as a tutorial. I can't understand anything about
1
2
3
4
std::vector<double> row;
std::copy(std::istream_iterator<double>(ifs),
          std::istream_iterator<double>(),
          std::back_inserter(row))
or
1
2
3
4
std::istream &read(std::istream &stream) { 
        std::copy(std::istream_iterator<double>(stream), 
              std::istream_iterator<double>(), 
              std::back_inserter(xyz));
In the meantime I go on with studying C++. Thanks for your attention.



Here are the references on the snippets posted:
http://www.cplusplus.com/reference/stl/vector/
http://www.cplusplus.com/reference/algorithm/copy/
http://www.cplusplus.com/reference/std/iterator/istream_iterator/
http://www.cplusplus.com/reference/std/iterator/back_inserter/

From the example posted, though, I don't think you need to do any of that. If you are only removing empty lines and adding that last integral flag, you could just use std::getline and a flag for when a line follows the removal of empty lines.

Do you need this data in some kind of data structure or just to transform it as above?
Last edited on
Probably you're right, I'm a newbie and I thought I need vector, copy, istream_iterator and so on, becouse of examples and tutorials I found in internet. However, I'm confused about object-oriented programming. Please, can you help me to find the right way? I'll be grateful for any tutorial or example. At present, I need just to trasform the textfile as above.
I know there are a lot of mistakes, but is it a good start?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include iostream.h
#include fstream.h
#include cstdlib.h

int main()
{

// open input file

    std::fstream ifs;
    ifs.open("file_name");

// create matrix as vector of vectors

    std::vector<std::vector<double>> matrix;
    int flag;

// read line

    std::string line;
    std::getline(ifs, line);

// if something went wrong (probably EOF), exit the loop

    if(!ifs) 
        break;

// if the line is empty, read row contents into vector and append flag 1

    if (line.empty())
        flag==1;
        continue;
        std::vector<double> row;
        std::copy(std::istream_iterator<double>(ifs),
                  std::istream_iterator<double>(),
                  std::back_inserter(row));
        row.push_back(flag)

// else read row contents into vector and append flag 0

    else
        flag==0;
        std::vector<double> row;
        std::copy(std::istream_iterator<double>(ifs),
                  std::istream_iterator<double>(),
                  std::back_inserter(row));
        row.push_back(flag)

    return matrix;
}
Unless I missed something it seems to me that you don't need to care about the content of this data except you need to detect the first and last element of a block?

So there would be no need to read double values in that case. You could just plough through the data reading one whole line at a time. When the line is blank, then you finish the last block (if any) and begin the next. The tricky part is going to be working out the flag value. You only know the end of block after you read a blank line. So you can't output the flag value of the current line until you are processing the next line.
How about something like this:
1
2
3
4
5
6
7
8
9
10
11
12
int flag = 1;
while( getline( ifs, line ) )
{
    if( line.empty() )
    {
        flag = 1;
        continue;
    }

    cout << line << " " << flag << endl;
    flag = 0;
}
Last edited on
If I'm correct, your comment is similar to moorecm's one, but I'm not so expert to understand it :-/
Yes, my aim is to delete blank lines and append a integer flag to every line: '1' if the line is the first of the block, '0' for other lines (and only one '9' to the last line). An example of the block:

-8.25000 0.00000 5.00000 1
-8.25000 2.40000 5.00000 0
...
-8.25000 7.68448 13.00000 0 (9 if it's the last block in the file)

I have no idea about how to append the flag, so I thought to build a matrix, read the coordinate x,y, and z from the text file, and add a column for the flags. You said I only know the end of the block but I think I know the beginning too: the text file starts with an empty line, then the lines of the firtst block, then another empty line, then the second block and so on. Maybe I didn't understand what you guys told me but I'm not a C++ programmer and my english is terrible, sorry.
Please, can you help me?
I feel so stupid... Do you suggest something like this?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include iostream.h
#include fstream.h
#include cstdlib.h

int main()
{

// open input file

    std::fstream ifs;
    ifs.open("file_name");

// read line

    std::string line;
    std::getline(ifs, line);

// append flag

    int flag = 1;

    while( getline( ifs, line ) )
    {
        if( line.empty() )
        {
            flag = 1;
            continue;
        }
        cout << line << " " << flag << endl;
        flag = 0;
    }

}
Now I'm looking for a simple code in order to remove empty lines, to find the last line and append a '9' flag to it. Back to study...
I edited the code in order to remove empty lines and squeeze whitespace in a single space. But I'm not sure this is the best (and correct) way. In the meantime I noticed that 'empty lines' are not empty: there is a single whitespace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include iostream.h
#include fstream.h
#include stream.h
#include cstdlib.h

int main()
{

// open input file

    std::ifstream ifs( "in_file.txt" );
    std::fstream ofs( "out_file.txt" );

// squeeze whitespace

   ifs >> word;
   out << word;

   while( in >> word )
   {
      ofs << " ";
      ofs << word;
   }

// read line

    std::string line;
    std::getline( ofs, line );

// append flag and remove 'empty lines'

    int flag = 1;

    while( getline( ofs, line ) )
    {
        if( line == "" )
        {
            flag = 1;
            continue;
        }
        cout << line << " " << flag << endl;
        flag = 0;
    }

ifs.close();
ofs.close();

}
Last edited on
I tried to compile test.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <fstream>
#include <stream>
#include <cstdlib>
using namespace std;

int main()
{

// open input file

    std::ifstream ifs( "in_file.txt" );
    std::fstream ofs( "out_file.txt" );

// squeeze whitespace

   std::string word;
   ifs >> word;
   ofs << word;

   while( ifs >> word )
   {
      ofs << " ";
      ofs << word;
   }

// read line

    std::string line;
    std::getline( ofs, line );

// append flag and remove 'empty lines'

    int flag = 1;

    while( getline( ofs, line ) )
    {
        if( line == "" )
        {
            flag = 1;
            continue;
        }
        cout << line << " " << flag << endl;
        flag = 0;
    }

ifs.close();
ofs.close();

}

I had the error message:
test.cpp:3:18: error: stream:
What does it mean?
I noticed I wrote stream and not string. Now I edited the source file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;

int main()
{

// open input file

    std::ifstream ifs( "in_file.txt" );
    std::fstream ofs( "out_file.txt" );

// squeeze whitespace

   std::string word;
   ifs >> word;
   ofs << word;

   while( ifs >> word )
   {
      ofs << " ";
      ofs << word;
   }

// read line

    std::string line;
    std::getline( ofs, line );

// append flag and remove 'empty lines'

    int flag = 1;

    while( getline( ofs, line ) )
    {
        if( line == " " )
        {
            flag = 1;
            continue;
        }
        cout << line << " " << flag << endl;
        flag = 0;
    }

ifs.close();
ofs.close();

}

and the outoput is:
gcc -o test test.cpp
/tmp/cc10PaH8.o: In function `main':
test.cpp:(.text+0x38): undefined reference to `std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(char const*, std::_Ios_Openmode)'
test.cpp:(.text+0x64): undefined reference to `std::basic_fstream<char, std::char_traits<char> >::basic_fstream(char const*, std::_Ios_Openmode)'
test.cpp:(.text+0x70): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
test.cpp:(.text+0x87): undefined reference to `std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
test.cpp:(.text+0x9e): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
test.cpp:(.text+0xb7): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
test.cpp:(.text+0xce): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
test.cpp:(.text+0xe5): undefined reference to `std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
test.cpp:(.text+0xf9): undefined reference to `std::basic_ios<char, std::char_traits<char> >::operator void*() const'
test.cpp:(.text+0x10e): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
test.cpp:(.text+0x122): undefined reference to `std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
test.cpp:(.text+0x15d): undefined reference to `std::cout'
test.cpp:(.text+0x162): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
test.cpp:(.text+0x172): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
test.cpp:(.text+0x182): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(int)'
test.cpp:(.text+0x18a): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
test.cpp:(.text+0x192): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))'
test.cpp:(.text+0x1ae): undefined reference to `std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
test.cpp:(.text+0x1c2): undefined reference to `std::basic_ios<char, std::char_traits<char> >::operator void*() const'
test.cpp:(.text+0x1de): undefined reference to `std::basic_ifstream<char, std::char_traits<char> >::close()'
test.cpp:(.text+0x1ea): undefined reference to `std::basic_fstream<char, std::char_traits<char> >::close()'
test.cpp:(.text+0x1f6): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
test.cpp:(.text+0x208): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
test.cpp:(.text+0x21a): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
test.cpp:(.text+0x22c): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
test.cpp:(.text+0x23e): undefined reference to `std::basic_fstream<char, std::char_traits<char> >::~basic_fstream()'
test.cpp:(.text+0x250): undefined reference to `std::basic_fstream<char, std::char_traits<char> >::~basic_fstream()'
test.cpp:(.text+0x265): undefined reference to `std::basic_ifstream<char, std::char_traits<char> >::~basic_ifstream()'
test.cpp:(.text+0x28f): undefined reference to `std::basic_ifstream<char, std::char_traits<char> >::~basic_ifstream()'
/tmp/cc10PaH8.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x2cd): undefined reference to `std::ios_base::Init::Init()'
test.cpp:(.text+0x2d2): undefined reference to `std::ios_base::Init::~Init()'
/tmp/cc10PaH8.o: In function `bool std::operator==<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*)':
test.cpp:(.text._ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_[bool std::operator==<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*)]+0x14): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::compare(char const*) const'
/tmp/cc10PaH8.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
/tmp/cc10PaH8.o:(.eh_frame+0x4b): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status

What's the problem, pleas? Have I to copy the called libraries in the same folder as test.cpp and in_file.txt?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;

int main()
{

// open input file

    std::ifstream ifs( "in_file.txt" );
//    std::fstream ofs( "out_file.txt" );
    std::ofstream ofs( "out_file.txt" ); // needs to be ofstream

// squeeze whitespace

   std::string word; // What is this supposed to do?
   ifs >> word;
   ofs << word;

   while( ifs >> word ) // Again, what is this supposed to do?
   {
      ofs << " ";
      ofs << word;
   }

// read line

    std::string line;
    std::getline( ofs, line );

// append flag and remove 'empty lines'

    int flag = 1;

    while( getline( ofs, line ) )
    {
        if( line == "" )
        {
            flag = 1;
            continue;
        }
        cout << line << " " << flag << endl;
        flag = 0;
    }

ifs.close();
ofs.close();

}


You are definitely getting closer. Mind you, this is actually quite a tricky problem and you still seem a bit shaky on the basics. It might be worth coming back to this later and set yourself a few, more simple, tasks first?
gcc does not automatically link to std C++ libraries.
So if you want to compile a C++ code using gcc, compile it as

gcc -o test test.cpp -lstdc++ to tell the compiler to include standard C++ libraries which will get the definition of iostream, removing your compilation error.

OR

Use g++, which automatically includes std C++ libraries.

g++ -o test test.cpp
Thank you all. I just compiled test.cpp by g++ and and launch test, but obviously it doesn' work. I know the source code is not correct.
Galik, you're right. Unfortunately I have to do that for work and I'm not a programmer - and the boss doens't care for that. So, here I am :-(
I need a C++ program to edit a software output file in order to be an input for a different software. Manual editing could be a problem becouse the file could be very big. So I downloaded some manuals and started studying C++. Of course I'm shaky, file and strings manipulating are always in the last chapters :-)
i'm look for help and I'm grateful for that, but I have not so much time. And I go on studying.

1
2
3
4
5
std::ofstream ofs( "out_file.txt" );
/* you're right, I wrote fstream
becouse I thought I need the same file
for output (it derives from in_file.txt)
and input (for flag appending) operations */


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// squeeze whitespace

/* I'm trying to read numbers (3 for each line)
and write to an other file,
with just a single whitespace
as numbers separator */

   std::string word; 
   ifs >> word;
   ofs << word;

   while( ifs >> word )
   {
      ofs << " ";
      ofs << word;
   }


Thanks for your patience :-/
Here I am again. This is my current code: I can delete 'empty lines' (they really consist in one whitespace plus the f.....g 'hidden' "\n" character) and append the integer flag at the end of the row. Next goals: squeeze whitespaces in order to have a structure like:

_x_y_z_flag

and change the last "0" flag into "9". Any suggestions, please? Thanks for your attention.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;

int main()
{

// open input file

    std::ifstream ifs( "in_file.txt" );
    std::ofstream ofs( "out_file.txt" );

// read line

    std::string line;
    std::getline( ifs, line );

// append flag

    std::string flag = " 1";
    int l;

    while( getline( ifs, line ) )
    {

         l = line.length();
         if( l == 2)
         {
             flag = " 1";
          continue;
          }
          line.erase(l-1);
          ofs << line << flag << endl;
          flag = " 0";
     }

ifs.close();
ofs.close();

}
Last edited on
Okay vaina, as I believe you and this doesn't look like a homework problem I'll give you a whole solution.

It works by printing the line it just read *without* the flag. It waits until it reads the *next* line before printing the flag for the previous line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <fstream>
#include <string>

int main()
{
	std::ifstream ifs("input.txt");
	std::ofstream ofs("output.txt");

	std::string line;

	// Skip leading blank lines
	while(std::getline(ifs, line) && line.empty());

	ofs << line; // output start of line

	int flag = 1; // first

	// get next line
	while(std::getline(ifs, line))
	{
		if(!line.empty())
		{
			// End previous line
			ofs << ' ' << flag << '\n';

			// after last set to first else zero
			flag = flag == 9 ? 1 : 0;

			// output start of next line
			ofs << line;
		}
		else
		{
			// we found the end so set flag
			// to 9 to append to previous line
			flag = 9;
		}
	}

	// Finish off last line
	ofs << ' ' << 9 << '\n';

	return 0;
}


But you're going to have to keep studying if your boss is going to ask you to do this kind of thing regularly :o)
Last edited on
Hi, Galik. Thanks for your help, but I still have a problem with the output file. The input file has not really empty lines, they consist in a whitespace plus \n. The structure (why is not possible to attach a file in this forum?!) is something like ("-" is a whitespace):

-\n
-----x1-----y1-----z1-\n
-----x2-----y2-----z2-\n
-----x3-----y3-----z3-\n
-----x4-----y4-----z4-\n

-----x5-----y5-----z5-\n
-----x6-----y6-----z6-\n
-----x7-----y7-----z7-\n

-----x8-----y8-----z8-\n
-----x9-----y9-----z9-\n
-----x10-----y10-----z10-\n
-----x11-----y11-----z11-\n
-----x12-----y12-----z12-\n
-----x13-----y13-----z13-\n
and so on.

That means your code doesn't recognize the 'empty lines', so it doesn't remove them and flags are not correct - except the FIRST "1" (but I need a "1" at the start of each coordinates block) and the "9" at the end of the file. An other problem is about /n at the end of each coordinates row: the flag is output on the next line:

-\n
1\n
-----x1-----y1-----z1-\n
0\n
-----x2-----y2-----z2-\n
0\n
-----x3-----y3-----z3-\n
0\n

For these reasons I wrote the code in the previous post, based on line.length and line.erase. I almost made the grade (see my previous post) and therefore I want to mix your code and mine, but I must understand your instructions.

1. I don't understand && line.empty() in the first while structure. The expression is true only if the program read a line AND this line is empty, am I right? So the the code should output in output.txt just the empty lines.... I can't understand what it's supposed to do (and I don't understand the meaning of "skip leading").

2. About the second while structure (I guess it's not nested in the first one). The code read the input file: if the line si not empty, then the code appends the flag ("1" at first time). The flag is 9? No, so flag becomes "0". Flag becomes "1" when the code read an other empty line and so on. I hope the conditional operator is clear to me.

So I have a problem with the 'hidden' \n in each line and the whitespace in the 'empty' lines. Any suggestions, please?
Now I understand what you were trying to do with the 'squeeze' thing.

The first while loop keeps looping until it read a non-blank line. Notice that instead of having a block after it while(cond){ } it has a semi-colon while(cond);. The semi-colon acts as an empty block. So it does nothing except keep reading lines until it finds one that is not blank.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

/**
 * Remove leading and trailing whitespace. Also
 * compress internal whitespace into a single space.
 */
std::string squeeze(const std::string& line)
{
	std::istringstream iss(line);
	std::ostringstream oss;

	std::string word;
	for(bool first = true; iss >> word; first = false)
	{
		oss << (first ? "" : " ") << word;
	}

	return oss.str();
}

int main()
{
	std::ifstream ifs("input.txt");
	std::ofstream ofs("output.txt");

	std::string line;

	// Skip leading blank lines
	// This line keeps looping until a non-blank line
	// is read. (it ends in semi-colon ; , rather than a block {})
	while(std::getline(ifs, line) && squeeze(line).empty());

	ofs << squeeze(line); // output start of (first non-blank) line

	int flag = 1; // first
	while(std::getline(ifs, line))
	{
		line = squeeze(line); // squeeze the line up
		if(!line.empty())
		{
			// End previous line
			ofs << ' ' << flag << '\n';

			// If flag equals 9 set flag to 1 otherwise set it to 0
			flag = flag == 9 ? 1 : 0;

			// output start of next line
			ofs << line;
		}
		else
		{
			// we found the end so set flag
			// to 9 to append to previous line
			flag = 9;
		}
	}

	// Finish off last line
	ofs << ' ' << 9 << '\n';

	return 0;
}
Last edited on
Thank you, Galik. Your code is also a good tutorial for me. My programming experience (other languages) consists only in computation, I was never involved in file or strings manipulating.
Topic archived. No new replies allowed.