2

I'm studying C programming, I know in C strcmp is used to compare two strings, but the comparing always contains the new line character, I want to ignore it. I know I can remove the new line character and then compare them, but is there any function that ignores the new line character automatically?

3 Answers3

2

This is one of those cases where it's easier to open code the function. I've made it test for equality strictly (i.e. not alphabetise), though that would be a relatively easy change.

Try this, which should actually do what the original questioner asked:

/* Compare two strings s1 and s2, assuming s1 is terminated
 * by \n or a NULL, and s2 is terminated by a NULL. A match
 * returns 0, a non-match returns 1.
 */
int
strcmpst1nl (const char * s1, const char * s2)
{
  char s1c;
  do
    {
      s1c = *s1;
      if (s1c == '\n')
          s1c = 0;
      if (s1c != *s2)
          return 1;
      s1++;
      s2++;
    } while (s1c); /* already checked *s2 is equal */
  return 0;
}

Interestingly this wasn't particularly elegant to do with a for loop. More elegant answers appreciated.

A more generalised routine to compare two strings where either can be terminated by a \n or a NULL (not quite what you asked) would be:

/* Compare two strings s1 and s2, assuming either is
 * terminated by \n or a NULL, A match
 * returns 0, a non-match returns 1.
 */
int
strcmpnl (const char *s1, const char *s2)
{
  char s1c;
  char s2c;
  do
    {
      s1c = *(s1++);
      s2c = *(s2++);
      if (s1c == '\n')
          s1c = 0;
      if (s2c == '\n')
          s2c = 0;
      if (s1c != s2c)
          return 1;
    }
  while (s1c);          /* already checked *s2 is equal */
  return 0;
}

Another less efficient route (assuming s1 is terminated by \n) would be:

#include <string.h>
#include <strings.h>
int
strcmpst1nl2 (const char *s1, const char *s2)
{
  int s1len, s2len;
  s1len = strlen (s1);
  s2len = strlen (s2);

  /* check strings are equal length without \n */
  if (s1len - 1 != s2len)
    return 1;

  /* we know s1len > 0, as s2len would be -1, so this is safe */
  if (s1[s1len - 2] != '\n')
    return 1;

  return bcmp (s1, s2, s1len - 1);
}
abligh
  • 24,573
  • 4
  • 47
  • 84
  • I think your answer is a little bit too custom, considering only the possibility that one of the 2 strings contains the termination character. Also, it won't work properly for some implementation of the new line (http://stackoverflow.com/questions/3267311/what-is-newline-character-n/3267323#3267323) – Antonio Jan 31 '14 at 09:17
  • 1
    That's what the question actually asked for ('but the comparing always contains the new line character'). However it would be trivial to fix the open coded version (which is the one I recommend) to treat `\n' as a terminator in either string by adding another `if` statement. I will modify the answer to show how. – abligh Jan 31 '14 at 09:20
1

You should first write a function that computes the length of the string, in which both the standard termination character and the endline character terminate the string. In doing so, I suggest you both check Line Feed and Carriage Return character (check here)
Then, you check that both strings have same length according to the previous definition.
If yes, you further check the string with strncmp (and using the found length as third parameter).

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
0

A function like the following could be used instead of strcmp(). It does the same thing, but ignores one (possible) trailing newline on the second string. It doesn't modify the strings.

int my_cmp(const char *str1, const char *str2)
{
  int r,n;

  /* Get length of str1, which is also the index of the 1st additional 
   * char in str2 
   */
  n = strlen(str1);

  /* Compare the first n chars */
  r = strncmp(str1,str2,n);

  /* If 1st n chars match, make sure next char in str2 is either the null char
   * or a newline followed by the null char.  Otherwise, return -1 since str2 is
   * longer (making str1 "less than" str2)
   */
  if ( !r && str2[n] && (str2[n] != '\n' || str2[n+1]) )
    return -1;

  return r;
}

Here's another one that ignores all newlines anywhere in either string:

int my_cmp(const char *str1, const char *str2)
{
  const unsigned char *a, *b;

  /* loop over both strings */
  for (a = str1, b = str2; ; a++, b++) {
    while (*a == '\n') a++; /* skip newlines in str1 */
    while (*b == '\n') b++; /* skip newlines in str2 */

    /* If we reach the end of either string (or both), one of
     * the if's below will terminate the loop */

    /* return if we're at end of both strings */
    if (!(*a || *b)) 
      return 0;

    /* positive return when str1's char is greater than str2's 
     * (or at end of str2) */
    if (*a > *b)
      return 1;

    /* negative return when str1's char is less than str2's 
     * (or at end of str1) */
    if (*a < *b)
      return -1;
  }

  return 0;
}

Of course, if you just need to ignore a single trailing newline it's easy to strip it off anyway (just locate it and overwrite it with '\0')...

Dmitri
  • 9,175
  • 2
  • 27
  • 34