Usuwanie końcowego znaku nowej linii z wejścia fgets ()

Próbuję pobrać dane od użytkownika i wysłać je do innej funkcji w gcc. Kod jest podobny do tego.

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

Okazuje się jednak, że na końcu ma znak newline \n. Więc jeśli wpiszę {[2] } to kończy się wysłaniem John\n. Jak usunąć \n i wysłać odpowiedni ciąg znaków.

Author: Jonathan Leffler, 2010-04-22

12 answers

Nieco brzydki sposób:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

Nieco dziwny sposób:

strtok(Name, "\n");

Zauważ, że funkcja strtok nie działa zgodnie z oczekiwaniami, jeśli użytkownik wprowadzi pusty łańcuch (tzn. naciska tylko Enter). Pozostawia znak \n nienaruszony.

Oczywiście są też inne.
 113
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-08 18:54:04

Być może najprostsze rozwiązanie wykorzystuje jedną z moich ulubionych mało znanych funkcji, strcspn():

buffer[strcspn(buffer, "\n")] = 0;

Jeśli chcesz, aby obsługiwał również '\r' (powiedzmy, jeśli strumień jest binarny):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

Funkcja zlicza liczbę znaków, aż trafi na '\r' lub '\n' (innymi słowy, znajdzie pierwszą '\r' lub '\n'). Jeśli w nic nie uderzy, zatrzymuje się na '\0' (zwracając Długość łańcucha).

Zauważ, że to działa dobrze, nawet jeśli nie ma newline, ponieważ strcspn zatrzymuje się na '\0'. W takim przypadku cała linia po prostu zastępuje '\0' '\0'.

 307
Author: Tim Čas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-11 18:54:56
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
 78
Author: James Morris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-31 18:55:26

Poniżej znajduje się szybkie podejście do usuwania potencjału '\n' z łańcucha zapisanego przez fgets().
Używa strlen(), z 2 testami.

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }

Teraz Użyj buffer i len w razie potrzeby.

Ta metoda ma dodatkową zaletę len dla kolejnego kodu. Może być łatwo szybszy niż strchr(Name, '\n'). Ref YMMV, ale obie metody działają.


buffer, z oryginału fgets() nie będzie zawierać w "\n" w pewnych okolicznościach:
A) linia była za długa na buffer więc tylko char poprzedzający '\n' jest zapisywany w buffer. Nieprzeczytane znaki pozostają w strumieniu.
B) ostatni wiersz w pliku nie zakończył się '\n'.

Jeśli input ma gdzieś wbudowane znaki null '\0', długość podana przez strlen() nie będzie zawierać '\n' lokalizacji.


Inne odpowiedzi " problemy:

  1. strtok(buffer, "\n"); Nie usuwa '\n', Gdy buffer jest "\n". Z tej odpowiedzi - poprawione po tej odpowiedzi, aby ostrzec przed to ograniczenie.

  2. Następujące błędy w rzadkich przypadkach, gdy pierwszy char czytany przez fgets() jest '\0'. Dzieje się tak, gdy wejście zaczyna się od wbudowanego '\0'. Wtedy buffer[len -1] staje się buffer[SIZE_MAX] dostęp do pamięci z pewnością spoza zakresu buffer. Coś, co haker może spróbować lub znaleźć w głupim czytaniu plików tekstowych UTF16. To był stan odpowiedź kiedy ta odpowiedź została napisana. Później nie-OP edytował go tak, aby zawierał kod podobny do tego czeku odpowiedzi dla "".

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  3. sprintf(buffer,"%s",buffer); jest niezdefiniowanym zachowaniem: Ref . Co więcej, nie zapisuje żadnych początkowych, oddzielających lub końcowych białych znaków. Teraz usunięty .

  4. [Edit ze względu na dobrą późniejszą odpowiedź nie ma żadnych problemów z 1 linerem buffer[strcspn(buffer, "\n")] = 0; innych niż wydajność w porównaniu do podejścia strlen(). Wydajność przy przycinaniu zwykle nie jest problemem, ponieważ kod robi We / Wy-czarną dziurę czasu procesora. Czy poniższy kod wymaga Długość łańcucha lub jest wysoce świadomy wydajności, użyj tego podejścia strlen(). W przeciwnym razie strcspn() jest dobrą alternatywą.

 15
Author: chux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-06 22:45:02

Bezpośrednie usunięcie "\n " z wyjścia fgets, jeśli każda linia ma "\N "

line[strlen(line) - 1] = '\0';

Inaczej:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}
 4
Author: Amitabha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-30 01:15:09

Dla pojedynczego' \n ' trmming,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

Dla wielokrotnego' \n ' przycinania,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}
 1
Author: Naveen Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-18 06:58:59

Tim Čas One liner jest niesamowity dla ciągów otrzymanych przez wywołanie do fgets, ponieważ wiesz, że zawierają pojedynczą nową linię na końcu.

Jeśli znajdujesz się w innym kontekście i chcesz obsługiwać ciągi znaków, które mogą zawierać więcej niż jeden znak nowej linii, możesz szukać strrspn. Nie jest to POSIX, co oznacza, że nie znajdziesz go na wszystkich Unices. Napisałem jeden na własne potrzeby.

/* Returns the length of the segment leading to the last 
   characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
  const char *ch;
  size_t len = strlen(s);

more: 
  if (len > 0) {
    for (ch = accept ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        len--;
        goto more;
      }
    }
  }
  return len;
}

Dla tych, którzy szukają odpowiednika Perl chomp w C, myślę, że to jest to (chomp usuwa tylko końcowe newline).

line[strrspn(string, "\r\n")] = 0;

Funkcja strrcspn:

/* Returns the length of the segment leading to the last 
   character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
  const char *ch;
  size_t len = strlen(s);
  size_t origlen = len;

  while (len > 0) {
    for (ch = reject ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        return len;
      }
    }
    len--;
  }
  return origlen;
}
 0
Author: Philippe A.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-30 20:17:19
 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}
Powinieneś spróbować. Ten kod w zasadzie pętli przez ciąg znaków, aż znajdzie "\n". Po znalezieniu' \n 'zostanie zastąpiony znakiem null' \0 '

Zauważ, że porównujesz znaki, a nie łańcuchy w tej linii, wtedy nie ma potrzeby używania strcmp ():

if(Name[i] == '\n') Name[i] = '\0';

Ponieważ będziesz używać pojedynczych cudzysłowów, a nie podwójnych cudzysłowów. Oto link o pojedynczych vs podwójnych cytatach, jeśli chcesz wiedzieć więcej

 0
Author: Matheus Martins Jerônimo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-17 23:22:14

Jeśli użycie getline jest opcją-nie zaniedbując jej problemów z bezpieczeństwem i jeśli chcesz nawiasować wskaźniki - możesz uniknąć funkcji łańcuchowych, ponieważ getline Zwraca liczbę znaków. Coś jak poniżej

#include<stdio.h>
#include<stdlib.h>
int main(){
char *fname,*lname;
size_t size=32,nchar; // Max size of strings and number of characters read
fname=malloc(size*sizeof *fname);
lname=malloc(size*sizeof *lname);
if(NULL == fname || NULL == lname){
 printf("Error in memory allocation.");
 exit(1);
}
printf("Enter first name ");
nchar=getline(&fname,&size,stdin);
if(nchar == -1){ // getline return -1 on failure to read a line.
 printf("Line couldn't be read.."); 
 // This if block could be repeated for next getline too
 exit(1);
}
printf("Number of characters read :%zu\n",nchar);
fname[nchar-1]='\0';
printf("Enter last name ");
nchar=getline(&lname,&size,stdin);
printf("Number of characters read :%zu\n",nchar);
lname[nchar-1]='\0';
printf("Name entered %s %s\n",fname,lname);
return 0;
}

Uwaga :[ kwestie bezpieczeństwa ] z {[1] }nie należy jednak zaniedbywać.

 0
Author: sjsam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 06:16:36
char name[1024];
unsigned int len;

printf("Enter your name: ");
fflush(stdout);
if (fgets(name, sizeof(name), stdin) == NULL) {
    fprintf(stderr, "error reading name\n");
    exit(1);
}
len = strlen(name);
if (name[len - 1] == '\n')
    name[len - 1] = '\0';
 -1
Author: draebek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-22 19:30:18

Poniższa funkcja jest częścią biblioteki przetwarzania łańcuchów, którą przechowuję na Githubie. Usuwa i niechciane znaki z ciągu znaków, dokładnie to, co chcesz

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

Przykładem użycia może być

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

Możesz sprawdzić inne dostępne funkcje, a nawet przyczynić się do projektu :) https://github.com/fnoyanisi/zString

 -1
Author: Fehmi Noyan ISI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-21 08:29:03

Spróbuj tego:

        int remove_cr_lf(char *str)
        {
          int len =0;


          len = strlen(str);

          for(int i=0;i<5;i++)
          {
            if (len>0)
            if (str[len-1] == '\n')
            {
              str[len-1] = 0;
              len--;
            }

            if (len>0)
            if (str[len-1] == '\r')
            {
              str[len-1] = 0;
              len--;
            }
          }

          return 0;
        }
 -1
Author: Balazs Kiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 13:38:40