Удаление завершающего символа новой строки из ввода fgets () - PullRequest
191 голосов
/ 22 апреля 2010

Я пытаюсь получить некоторые данные от пользователя и отправить их другой функции в 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 и отправить правильную строку.

Ответы [ 12 ]

361 голосов
/ 11 февраля 2015

Возможно, самое простое решение использует одну из моих любимых малоизвестных функций, 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'.

121 голосов
/ 22 апреля 2010

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

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

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

strtok(Name, "\n");

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

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

82 голосов
/ 22 апреля 2010
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
16 голосов
/ 01 января 2015

Ниже приведен быстрый способ удаления потенциального '\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] = '\0';
  }

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

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


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

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


Некоторые вопросы, связанные с ответами:

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

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

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

3 голосов
/ 30 июня 2013

Прямое удаление '\ 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';
}
1 голос
/ 16 марта 2015

Для одиночного тримминга '\ n',

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';
  }
}
0 голосов
/ 06 февраля 2019

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

#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 голосов
/ 09 мая 2018

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

        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;
        }
0 голосов
/ 25 ноября 2017

Если используется 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 не должны игнорироваться.

0 голосов
/ 17 сентября 2017
 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';

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

...