0

I am asked to squeezed two or more consecutive blank lines in the input as one blank line in the output. So I have to use Cygwin to do I/O or test it. Example: ./Lab < test1.txt > test2.txt

my code is:

   int main(void){

    format();
    printf("\n");
    return 0;
}


void format(){
    int c;
    size_t nlines = 1;
    size_t nspace = 0;
    int spaceCheck = ' '; 

    while (( c= getchar()) != EOF ){

        /*TABS*/
        if(c == '\t'){
            c = ' ';
        }
        /*SPACES*/
        if (c ==' '){/*changed from isspace(c) to c==' ' because isspace is true for spaces/tabs/newlines*/
           /* while (isspace(c = getchar())); it counts while there is space we will put one space only */
            if(nspace > 0){
                continue;
            }
            else{
                putchar(c);
                nspace++;
                nlines = 0;
            }

        }


        /*NEW LINE*/
        else if(c == '\n'){
            if(nlines >0){
                continue;
            }
            else{
                putchar(c);
                nlines++;
                nspace = 0;
            }

        }   


        else{
            putchar(c);
            nspace = 0;
            nlines = 0;

        }       







    }

}

However my test2.txt doesn't have the result I want. Is there something wrong in my logic/code?

  • 1
    put an `else { nlines = 0; }` to reset the counter. – cs95 Jun 07 '17 at 10:12
  • the same logic with this question: https://stackoverflow.com/questions/44402182/why-isnt-this-code-compressing-spaces-correctly/44402251#44402251 – Jimmy Jun 07 '17 at 10:24
  • 1
    `c = '\n';` is absolutely in vain if `c == '\n'` applies already... – Aconcagua Jun 07 '17 at 10:33
  • @Shiva no it still doesn't work. but thanks for answering – dyingStudent Jun 07 '17 at 10:43
  • @Aconcagua I just want to set it to only one new blank line. It doesn't matter if there's already a blank line. – dyingStudent Jun 07 '17 at 10:43
  • @dyingStudent Your new code should remove *all* blank lines. If you want to leave one, you should try `if(nlines > 1)`, because you need one, of course, for the single remaining empty line, but *another* one for the preceding non-empty one. That's why I needed NL1 and NL2 states in my solution, too... – Aconcagua Jun 09 '17 at 06:42
  • By the way: Do you want to consider whitespace only lines as blank lines, too, or not? Do you want to entirely remove leading/trailing whitespace? – Aconcagua Jun 09 '17 at 06:50

2 Answers2

1

To dissect this:

if(c == '\n') {
        nlines++;

is nlines ever reset to zero?

        if(nlines > 1){
            c = '\n';

And what happens on the third \n in sequence? will nlines > 1 be true? Think about it!

        }
}
putchar(c);

I don't get this: You unconditionally output your character anyways, defeating the whole purpose of checking whether it's a newline.

A correct solution would set a flag when c is a newline and not output anything. Then, when c is NOT a newline (else branch), output ONE newline if your flag is set and reset the flag. I leave the code writing to you now :)

1

You provide too little code, the interesting part would be the loop around the code you posted...

What you actually have to do there is skipping the output:

FILE* file = ...;
char c, prev = 0;
while((c = fgets(file)) != EOF)
{
    if(c != '\n' || prev != '\n')
        putchar(c);
    prev = c;
}

If we have an empty line following another one, then we encounter two subsequent newline characters, so both c and prev are equal to '\n', which is the situation we do not want to output c (the subsequent newline) – and the inverse situation is any one of both being unequal to '\n', as you see above – and only then you want to output your character...

Side note: prev = 0 – well, I need to initalise it to anything different than a newline, could as well have been 's' – unless, of course, you want to skip an initial empty line, too, then you would have to initialise it with '\n'...

Edit, referring to your modified code: Edit2 (removed references to code as it changed again)

As your modified code shows that you do not only want to condense blank lines, but whitespace, too, you first have to consider that you have two classes of white space, on one hand, the newlines, on the other, any others. So you have to differentiate appropriately.

I recommend now using some kind of state machine:

#define OTH  0
#define WS   1
#define NL1  2
#define NL2  3

int state = OTH;

while (( c= getchar()) != EOF )
{
    // first, the new lines:
    if(c == '\n')
    {
        if(state != NL2)
        {
            putchar('\n');
            state = state == NL1 ? NL2 : NL1;
        }
    }
    // then, any other whitespace
    else if(isspace(c))
    {
        if(state != WS)
        {
            putchar(' ');
            state = WS;
        }
    }
    // finally, all remaining characters
    else
    {
        putchar(c);
        state = OTH;
    }
}

First differentiation occurs to the current character's own class (newline, whitespace or other), second differentiation according to the previous character's class, which defines the current state. Output occurs always for any non-whitespace character or if the two subsequent whitespace characters only, if they are of different class (newline is a little specific, I need two states for, as we want to leave one blank line, which means we need two subsequent newline characters...).

Be aware: whitespace only lines do not apply as blank lines in above algorithm, so they won't be eliminated (but reduced to a line containing one single space). From the code you posted, I assume this is intended...

For completeness: This is a variant removing leading and trailing whitespace entirely and counting whitespace-only lines as empty lines:

if(c == '\n')
{
    if(state != NL2)
    {
        putchar('\n');
        state = state == NL1 ? NL2 : NL1;
    }
}
else if(isspace(c))
{
    if(state == OTH)
        state = WS;
}
else
{
    if(state == WS)
    {
        putchar('');
    }
    putchar(c);
    state = OTH;
}

Secret: Only enter the whitespace state, if there was a non-ws character before, but print the space character not before you encounter the next non-whitespace.

Coming to the newlines - well, if there was a normal character, we are either in state OTH or WS, but none of the two NL states. If there was only whitespace on the line, the state is not modified, thus we remain in the corresponding NL state (1 or 2) and skip the line correspondingly...

Aconcagua
  • 24,880
  • 4
  • 34
  • 59