2

I am making a code to parse some input data and write it to a file in a special formatting. I am removing a newline from each string token as so:

token[strlen(token)-2] ='\0'

It is -2 because the last element is \0. This much works. However, the final element of the input data does NOT have a newline, so using just that ends up removing the second-to-last character from the last input set.

original input: 0.38
after running it through the removal: 0.3

The obvious solution is to check if the newline is there before removing. I do this:

if(token[strlen(token)-2] =='\n') token[strlen(token)-2] ='\0';

However, after adding the if clause, the newline is no longer removed! What am i doing wrong? Snippit from the whole code:

    while((token = strsep(&line, ",")) != NULL){
        if(x++ == 1){
            fwrite("    <item>\n", 11, 1, fw);
            fwrite("        <name>", 14, 1, fw);
            fwrite(token, strlen(token), 1, fw);
            fwrite("</name>\n", 8, 1, fw);
        }
        else if(isdigit(token[0])) {
            if(token[strlen(token)-2] =='\n') token[strlen(token)-2] ='\0';
            fwrite("        <SPC>", 13, 1, fw);
            fwrite(token, strlen(token), 1, fw);
            fwrite("</SPC>\n", 7, 1, fw);
            fwrite("    </item>\n", 12, 1, fw);
        }
    }
elder4222
  • 355
  • 2
  • 15
  • It isn't obvious at first glance what the problem is. Maybe you should just use `char *p = strchr(token, '\n'); if (p) *p = 0;`? –  Apr 14 '13 at 15:14
  • use a loop: `for(len=strlen(token); len && token[len-1] == '\n'; len--) { token[len] = 0; }` Note: this can be extended to cache the '\r', too. – wildplasser Apr 14 '13 at 15:15

4 Answers4

2

Your newline should be at line[strlen(line)-1], but you may work under Windows where a newline actually consists of a carriage return followed by a newline. This would explain why line[strlen(line)-2]='\0' is successful in removing the end-of-line, but the test fails.

Bryan Olivier
  • 5,207
  • 2
  • 16
  • 18
  • 2
    In which case, you should add that, the OP should check for `\r` instead of `\n` at `strlen(token)-2`. – Daniel Fischer Apr 14 '13 at 15:15
  • I am on mac-the first time I tried, i used `-1` but it didn't remove any newlines; it did when I used `-2` – elder4222 Apr 14 '13 at 15:17
  • 1
    Personally I would check for both the `\r` and the `\n` and make sure the string is long enough to contain both. – Bryan Olivier Apr 14 '13 at 15:18
  • @elder4222 That's however something that will break on Linux systems. If you need something resembling portability, check from the end for either of `\r` and `\n`. – Daniel Fischer Apr 14 '13 at 15:25
2

I think your problem is using -2 instead of -1, use this function to remove whitespace from the right side of the string:

#include <ctype.h> 
/* remove whitespace from the right */ 
void rtrim(char *s) {
    char *p;
    for (p = s + strlen(s) - 1; p >= s && isspace(p[0]); p--);
    p[1] = 0;
} 
perreal
  • 94,503
  • 21
  • 155
  • 181
2
size_t len;
for(len=strlen(token); len && (token[len-1] == '\r' || token[len-1] == '\n'); len--) {
   token[len] = 0;
   }

or, you could use strcspn():

size_t len;
len = strcspn(token, "\r\n" );
token[len] = 0;

Or, as a one-liner:

token [ token + strcspn(token, "\r\n" )] = 0;

Do note that the first fragment only removes the trailing '\r's and '\n's; the srcspn() fragments remove everything from the first '\r' or '\n' they encounter.

wildplasser
  • 43,142
  • 8
  • 66
  • 109
2

For the sake of flexibility (no character counting, no character literals) I'd do:

#include <string.h>

...

char * rtrim(char * str, const char * del)
{
  if (str)
  {
    char * pc;
    while (pc = strpbrk(str, del))
    {
      *pc = 0;
    }
  }

  return str;
}

...

char * line;

... /* let line point to some string */

/* to remove any kind of line end, call it like this: */
line = rtrim(line, "\n\r");

This solution covers *IX, ms and mac line ends, and also would survive things like:

#define char wchar_t
alk
  • 69,737
  • 10
  • 105
  • 255