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

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

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

тем не менее, я считаю, что у него есть новая строка n символ в конце. Итак, если я войду John это заканчивается отправкой Johnn. Как удалить это n и отправить соответствующую строку.

12 ответов


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

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

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

strtok(Name, "\n");

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

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


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

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

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

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

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

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


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

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

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

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

теперь использовать buffer и len по мере необходимости.

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


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

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


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

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

  2. следующее терпит неудачу в редких случаях, когда первый char читать fgets() is ''. Это происходит, когда ввод начинается со встроенного ''. Тогда 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] = '';
    }
    
  3. sprintf(buffer,"%s",buffer); неопределено поведение: Ref. Кроме того, он не сохраняет никаких ведущих, разделяющих или завершающих пробелов. Теперь удалены.

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


Direct для удаления '\n 'из вывода fgets, если каждая строка имеет '\n'

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

иначе:

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

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

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

для множественной "\ N " обрезки,

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

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

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

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

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

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

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

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

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


при использовании 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]='';
printf("Enter last name ");
nchar=getline(&lname,&size,stdin);
printf("Number of characters read :%zu\n",nchar);
lname[nchar-1]='';
printf("Name entered %s %s\n",fname,lname);
return 0;
}

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


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

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

int zstring_search_chr(const char *token,char s){
    if (!token || s=='')
        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='';
        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


попробуй это:

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