it-swarm.com.de

Hinterstehendes Zeilenvorschubzeichen aus der Eingabe fgets () entfernen

Ich versuche, einige Daten vom Benutzer zu erhalten und an eine andere Funktion in gcc zu senden. Der Code ist so ähnlich.

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 ein Newline \n-Zeichen hat. Wenn ich also John eingebe, wird John\n gesendet. Wie entferne ich diesen \n und sende eine richtige Zeichenfolge?.

182
sfactor

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 Funktion strtok nicht wie erwartet funktioniert, wenn der Benutzer eine leere Zeichenfolge eingibt (d. H. Nur Enter drückt). Das \n-Zeichen bleibt erhalten.

Es gibt natürlich auch andere.

117
Jerry Coffin

Möglicherweise verwendet die einfachste Lösung eine meiner beliebtesten, wenig bekannten Funktionen: strcspn() :

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

Wenn Sie möchten, dass es auch mit '\r' (z. B. wenn der Stream binär ist) behandelt wird:

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

Die Funktion zählt die Anzahl der Zeichen, bis sie einen '\r' oder einen '\n' trifft (mit anderen Worten, sie findet den ersten '\r' oder '\n'). Wenn es nichts trifft, stoppt es am '\0' (gibt die Länge des Strings zurück).

Beachten Sie, dass dies auch ohne Newline funktioniert, da strcspn bei '\0' stoppt. In diesem Fall ersetzt die gesamte Zeile einfach '\0' durch '\0'.

334
Tim Čas
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
82
James Morris

Im Folgenden finden Sie einen schnellen Ansatz, um einen potenziellen '\n' aus einem von fgets() gespeicherten String zu entfernen.
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';
  }

Verwenden Sie nun buffer und len nach Bedarf.

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


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

Wenn die Eingabe irgendwo eingebettete Nullzeichen '\0' enthält, wird die '\n'-Position in der von strlen() angegebenen Länge nicht berücksichtigt.


Einige andere Antworten: 

  1. strtok(buffer, "\n"); kann den '\n' nicht entfernen, wenn buffer"\n" ist. Von dieser Antwort - nach dieser Antwort abgeändert, um vor dieser Einschränkung zu warnen. 

  2. Das Folgende schlägt in seltenen Fällen fehl, wenn die erste char, die von fgets() gelesen wird, '\0' ist. Dies geschieht, wenn die Eingabe mit einem eingebetteten '\0' beginnt. Dann wird buffer[len -1]buffer[SIZE_MAX] für den Zugriff auf den Arbeitsspeicher bestimmt außerhalb des zulässigen Bereichs von buffer. Etwas, das ein Hacker versucht oder findet, wenn er UTF16-Textdateien dumm liest. Dies war der Zustand einer Antwort als diese Antwort geschrieben wurde. Später bearbeitete ein Nicht-OP den Code, um den Code dieser Antwort auf "" zu prüfen.

    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 nachlaufenden Leerzeichen gespeichert. Jetzt gelöscht .

  4. [Bearbeiten wegen guter späterer Antwort ] Es gibt keine Probleme mit dem 1-Liner buffer[strcspn(buffer, "\n")] = 0; außer der Leistung im Vergleich zum strlen()-Ansatz. Die Leistung beim Trimmen ist normalerweise kein Problem, wenn der Code E/A-Vorgänge ausführt - ein schwarzes Loch der CPU-Zeit. Wenn der folgende Code die Länge der Zeichenfolge benötigt oder sehr leistungsorientiert ist, verwenden Sie diesen strlen()-Ansatz. Ansonsten ist strcspn() eine gute Alternative.

16
chux

Direkt zum Entfernen von '\ n' aus der Ausgabe von 'fgets', 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';
}
3
Amitabha

Für ein einzelnes '\ n'

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

zum mehrfachen '\ n' Trimmen

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}
1
Naveen Kumar

Mein Neuling Weg ;-) Bitte lass es mich wissen, wenn das stimmt. Es scheint für alle meine Fälle zu funktionieren:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //Prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 0;
}
0
Pawel Flajszer

Tim Čas One Liner ist für Strings, die durch einen Aufruf von Fgets erhalten werden, erstaunlich, da Sie wissen, dass sie am Ende nur eine einzige Zeile enthalten. 

Wenn Sie sich in einem anderen Kontext befinden und Strings behandeln möchten, die mehrere Zeilenumbrüche 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 schrieb einen für meine eigenen Bedürfnisse.

/* 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 nachgestellte Zeile).

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

Die strrcspn-Funktion:

/* 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
Philippe A.

Wenn die Verwendung von getline eine Option ist - Die Sicherheitsprobleme nicht vernachlässigen und wenn Sie Zeiger abstützen möchten - können Sie Zeichenfolgenfunktionen vermeiden, da getline die Anzahl der Zeichen zurückgibt. Etwas wie unten

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

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

0
sjsam