Entfernen des nachgestellten Zeilenvorschubzeichens von der Eingabe fgets ()

Ich versuche, einige Daten vom Benutzer zu erhalten und sie an eine andere function in gcc zu senden. Der Code ist in etwa so.

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

Ich finde jedoch, dass es am Ende einen newline \n Charakter hat. Wenn ich also John betrete, wird John\n . Wie entferne ich das \n und sende eine richtige Zeichenfolge.

   

Der etwas hässliche Weg:

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

Der etwas seltsame Weg:

 strtok(Name, "\n"); 

Beachten Sie, dass die function strtok nicht wie erwartet funktioniert, wenn der Benutzer eine leere Zeichenfolge eingibt (dh nur Enter drückt). Es lässt das \n Zeichen intakt.

Es gibt natürlich auch andere.

Vielleicht die einfachste Lösung verwendet eine meiner Lieblings-wenig bekannte functionen, strcspn() :

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

Wenn Sie möchten, dass es auch '\r' (zB wenn der Stream binär ist):

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

Die function zählt die Anzahl der Zeichen, bis sie ein '\r' oder ein '\n' trifft (mit anderen Worten, sie findet das erste '\r' oder '\n' ). Wenn es nichts trifft, stoppt es bei '\0' (gibt die Länge der Zeichenfolge zurück).

Beachten Sie, dass dies auch dann funktioniert, wenn keine neue strcspn vorhanden ist, da strcspn bei '\0' stoppt. In diesem Fall ersetzt die gesamte Zeile einfach '\0' durch '\0' .

 size_t ln = strlen(name) - 1; if (*name && name[ln] == '\n') name[ln] = '\0'; 

Im Folgenden finden Sie einen schnellen Lösungsansatz, um ein mögliches '\n' aus einer Zeichenfolge zu entfernen, die von fgets() gespeichert wurde.
Es verwendet strlen() , mit 2 Tests.

 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'; } 

Jetzt benutze buffer und len wie benötigt.

Diese Methode hat den Vorteil eines len Werts für den nachfolgenden Code. Es kann leicht schneller sein als strchr(Name, '\n') . Ref YMMV, aber beide Methoden funktionieren.


buffer , von der ursprünglichen fgets() wird nicht in "\n" unter bestimmten Umständen enthalten:
A) Die Zeile war zu lang für den buffer so dass nur ein char vor dem '\n' im buffer gespeichert wird. Die ungelesenen Zeichen verbleiben im Stream.
B) Die letzte Zeile in der Datei endete nicht mit einem '\n' .

Wenn die Eingabe die Nullzeichen '\0' irgendwo eingebettet hat, enthält die von strlen() gemeldete Länge nicht die Position '\n' .


Einige andere Antworten:

  1. strtok(buffer, "\n"); Fehler beim Entfernen des '\n' wenn der buffer "\n" . Von dieser Antwort – nach dieser Antwort geändert, um vor dieser Einschränkung zu warnen.

  2. Der folgende fgets() schlägt in seltenen Fällen fehl, wenn das erste fgets() das von fgets() gelesen wird, '\0' . Dies geschieht, wenn die Eingabe mit einem eingebetteten '\0' beginnt. Dann wird der buffer[len -1] zum buffer[SIZE_MAX] , der sicher auf Speicher außerhalb des legitimen Bereichs des buffer zugreift. Etwas, das ein Hacker versuchen könnte, wenn er UTF16-Textdateien töricht liest. Dies war der Zustand einer Antwort, als diese Antwort geschrieben wurde. Später hat ein Nicht-OP es bearbeitet, um Code wie die Antwort der Antwort für "" einzuschließen.

     size_t len = strlen(buffer); if (buffer[len - 1] == '\n') { // FAILS when len == 0 buffer[len -1] = '\0'; } 
  3. sprintf(buffer,"%s",buffer); ist undefiniertes Verhalten: Ref . Außerdem werden keine führenden, trennenden oder nachgestellten Leerzeichen gespeichert. Jetzt gelöscht

  4. [Edit wegen guter späterer Antwort ] Es gibt keine Probleme mit dem 1 Liner- buffer[strcspn(buffer, "\n")] = 0; strlen() performance im Vergleich zum strlen() Ansatz. Die performance beim Trimmen ist normalerweise kein Problem, wenn der Code I / O macht – ein schwarzes Loch der CPU-Zeit. Wenn der folgende Code die Länge der Zeichenfolge benötigt oder sehr leistungsbewusst ist, verwenden Sie die strlen() . strcspn() ist die strcspn() eine gute Alternative.

Direkt, um das ‘\ n’ aus der Ausgabe von fgets zu entfernen, wenn jede Zeile ‘\ n’ hat

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

Andernfalls:

 void remove_newline_ch(char *line) { int new_line = strlen(line) -1; if (line[new_line] == '\n') line[new_line] = '\0'; } 

Für einzelne ‘\ n’ tremming,

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

für mehrere ‘\ n’ Trimmen,

 void remove_new_line(char* string) { size_t length = strlen(string); while(length>0) { if(string[length-1] == '\n') { --length; string[length] ='\0'; } else break; } } 
  for(int i = 0; i < strlen(Name); i++ ) { if(Name[i] == '\n') Name[i] = '\0'; } 

Du solltest es versuchen. Dieser Code durchläuft die Zeichenfolge im Grunde so lange, bis das '\ n' gefunden wird. Wenn es gefunden wird, wird '\ n' durch den Null-Zeichen-Terminator '\ 0' ersetzt.

Beachten Sie, dass Sie in dieser Zeile Zeichen und keine Zeichenfolgen vergleichen. Dann müssen Sie strcmp () nicht verwenden:

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

da Sie einfache Anführungszeichen und keine Anführungszeichen verwenden. Hier ist ein Link über einzelne vs doppelte Anführungszeichen, wenn Sie mehr wissen möchten

 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'; 

Die folgende function ist Teil der String-Verarbeitungsbibliothek, die ich auf Github verwalte. Es entfernt und unerwünschte Zeichen aus einer Zeichenfolge, genau was Sie wollen

 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; } 

Eine Beispielanwendung könnte sein

 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 

Vielleicht möchten Sie andere verfügbare functionen überprüfen oder sogar zum Projekt beitragen 🙂 https://github.com/fnoyanisi/zString

Tim Cas Ein Liner ist erstaunlich für Streicher, die man durch einen Aufruf an Fgets erhält, weil man weiß, dass sie am Ende einen einzigen Zeilenumbruch enthalten.

Wenn Sie sich in einem anderen Kontext befinden und mit Strings arbeiten möchten, die mehr als einen Zeilenumbruch enthalten können, suchen Sie möglicherweise nach strrspn. Es ist nicht POSIX, was bedeutet, dass Sie es nicht auf allen Unices finden werden. Ich habe einen für meine eigenen Bedürfnisse geschrieben.

 /* 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; } 

Für diejenigen, die nach einem Perl-Chomp-Äquivalent in C suchen, denke ich, dass dies der Fall ist (chomp entfernt nur die abschließende Newline).

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

Die function 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; } 

Wenn die Verwendung von getline eine Option ist – die Sicherheitsprobleme nicht zu vernachlässigen und wenn Sie pointers spannen möchten – können Sie String-functionen vermeiden, da die getline die Anzahl der Zeichen zurückgibt. Etwas wie unten

 #include #include 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; } 

Hinweis : Die [ Sicherheitsprobleme ] mit getline sollten jedoch nicht vernachlässigt werden.

Probier diese:

  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; }