Удаление конечного символа новой строки из входа fgets()

Я пытаюсь получить некоторые данные от пользователя и отправить его в другую функцию в gcc. Код выглядит примерно так.

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

Однако, я обнаружил, что в конце он имеет символ новой строки \n. Поэтому, если я введу John, он отправит John\n. Как удалить этот \n и отправить правильную строку.

Ответ 1

Немного уродливый способ:

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

Немного странный способ:

strtok(Name, "\n");

Обратите внимание, что функция strtok работает не так, как ожидалось, если пользователь вводит пустую строку (т.е. нажимает только Enter). Он оставляет символ \n неповрежденным.

Конечно, есть и другие.

Ответ 2

Возможно, самое простое решение использует одну из моих любимых малоизвестных функций, strcspn():

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

Если вы хотите, чтобы он также обрабатывал '\r' (скажем, если поток двоичный):

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

Функция подсчитывает количество символов до тех пор, пока не достигнет значения '\r' или '\n' (другими словами, он найдет первые '\r' или '\n'). Если он ничего не ударил, он останавливается на '\0' (возвращает длину строки).

Обратите внимание, что это отлично работает, даже если нет новой строки, потому что strcspn останавливается на '\0'. В этом случае вся строка просто заменяет '\0' на '\0'.

Ответ 3

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

Ответ 4

Ниже приведен быстрый подход к удалению потенциального '\n' из строки, сохраненной fgets().
Он использует strlen(), с двумя тестами.

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

Теперь используйте buffer и len по мере необходимости.

Этот метод имеет боковое преимущество значения len для последующего кода. Это может быть быстрее, чем strchr(Name, '\n'). Ссылка YMMV, но оба метода работают.


buffer, из оригинала fgets() в некоторых случаях не будет находиться в "\n":
A) Линия была слишком длинной для buffer, поэтому только char перед '\n' сохраняется в buffer. В потоке остаются непрочитанные символы.
B) Последняя строка в файле не заканчивается символом '\n'.

Если ввод содержит встроенные нулевые символы '\0' в нем где-то, длина, сообщенная strlen(), не будет содержать расположение '\n'.


Некоторые другие вопросы ответов:

  • strtok(buffer, "\n"); не удается удалить '\n', когда buffer - "\n". Из этого answer - изменен после этого ответа, чтобы предупредить об этом ограничении.

  • Ниже приводятся ошибки в редких случаях, когда первый char, читаемый fgets(), равен '\0'. Это происходит, когда ввод начинается со встроенного '\0'. Тогда buffer[len -1] становится buffer[SIZE_MAX] доступным к памяти, конечно, вне допустимого диапазона buffer. Что-то хакер может попытаться найти в глупости чтения текстовых файлов UTF16. Это было состояние ответа , когда этот ответ был написан. Позже не-OP отредактировал его, чтобы включить код, подобный этой проверке ответа на "".

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  • sprintf(buffer,"%s",buffer); - поведение undefined: Ссылка. Кроме того, он не сохраняет никаких ведущих, разделяющих или завершающих пробелов. Теперь удален.

  • [Изменить из-за хорошего более позднего ответа ] Нет проблем с 1 лайнером buffer[strcspn(buffer, "\n")] = 0;, отличным от производительности, по сравнению с подходом strlen(), Производительность при обрезке обычно не является проблемой, поскольку код вводит I/O - черную дыру процессорного времени. Если следующий код требует длины строки или имеет высокую производительность, используйте этот подход strlen(). Иначе strcspn() является прекрасной альтернативой.

Ответ 5

Прямо удалить "\n" из вывода fgets, если каждая строка имеет "\n"

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

В противном случае:

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

Ответ 6

Для одиночного '\n' trmming,

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

для нескольких "\n" обрезки,

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

Ответ 7

Тим Čas один лайнер поражает строки, полученные вызовом fgets, потому что вы знаете, что они содержат одну новую строку в конце.

Если вы находитесь в другом контексте и хотите обрабатывать строки, которые могут содержать более одной новой строки, вы можете искать strrspn. Это не POSIX, то есть вы не найдете его во всех Unices. Я написал один для своих собственных нужд.

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

Для тех, кто ищет эквивалент Perl chomp в C, я думаю, что это он (chomp только удаляет конечную новую строку).

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

Функция 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;
}

Ответ 8

Я лично использую следующий метод при обработке строк из fgets:

if(str[strlen(str) - 1] == '\n')
{
    str[strlen(str) - 1] = '\0';
}

Вы также можете использовать функции, упомянутые другими в предыдущих ответах, но мне нравится простота этого метода.

Ответ 9

Простейшие способы:

while(fgets(Name, 512, fp) != NULL)
{
if (Name[0] == '\n' || Name[0] == '\r')
    continue;
strtok(Name, "\n");
...
}

Ответ 10

Если использовать getline - это вариант. Не пренебрегая его проблемами безопасности, и если вы хотите привязать указатели, вы можете избежать строковых функций, так как getline возвращает количество символов. Что-то вроде ниже

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

Примечание. [ проблемы безопасности] с getline не следует пренебрегать хотя.

Ответ 11

Это так просто:

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

Ответ 12

Мой путь новичка ;-) Пожалуйста, дайте мне знать, если это правильно. Кажется, работает для всех моих случаев:

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

Ответ 13

Нижеприведенная функция является частью библиотеки обработки строк, которую я поддерживаю в Github. Он удаляет и нежелательные символы из строки, именно то, что вы хотите

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

Пример использования может быть

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

Вы можете проверить другие доступные функции или даже внести свой вклад в проект:) https://github.com/fnoyanisi/zString

Ответ 14

 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

Вы должны попробовать. Этот код в основном проходит через строку до тех пор, пока не найдет "\n". Когда он найдет '\n', будет заменен нулевым символьным терминатором '\ 0'

Обратите внимание, что вы сравниваете символы, а не строки в этой строке, тогда нет необходимости использовать strcmp():

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

поскольку вы будете использовать одинарные кавычки, а не двойные кавычки. Здесь ссылка о одиночных или двойных кавычках, если вы хотите узнать больше

Ответ 15

Попробуйте следующее:

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

Ответ 16

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

Ответ 17

Самая большая причина получения "\n" после получения ввода от пользователя заключается в том, что вы используете scanf();. Сначала у меня была такая же проблема, но я понял, что getch(); является хорошей альтернативой для подобных проблем, но вам придется использовать escape-символ, такой как * или%, или что-то еще подобное, чтобы указать конец вход.

Попробуйте следующее:

char var[50];
int pos=0;
printf("Enter your name:");
while(var[pos]!="%")
{
    var[pos]=getch();
    pos++;
}