[c] 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하고 적절한 문자열을 보내 려면 어떻게해야합니까?



답변

약간 못생긴 방법 :

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

약간 이상한 방법 :

strtok(Name, "\n");

strtok사용자가 빈 문자열을 입력하면 (예 : Enter 만 누름) 이 기능은 예상대로 작동하지 않습니다. \n캐릭터를 그대로 둡니다 .

물론 다른 것도 있습니다.


답변

아마도 가장 간단한 해결책은 내가 좋아하는 거의 알려지지 않은 기능 중 하나를 사용하는 것입니다 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'.


답변

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


답변

아래는에 '\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'위치가 포함되지 않습니다 .


다른 답변의 문제 :

  1. strtok(buffer, "\n");(가) 제거에 실패 '\n'할 때 buffer입니다 "\n". 이 답변에서 -이 제한 이후에 경고하기 위해이 답변 이후 수정되었습니다.

  2. 첫 번째 charby by fgets()가 인 경우는 드물지만 다음에 실패합니다 '\0'. 입력이 포함 된로 시작될 때 발생합니다 '\0'. 이어서 buffer[len -1]된다 buffer[SIZE_MAX]의 정상적인 범위 밖에 확실히 액세스 메모리 buffer. 해커가 UTF16 텍스트 파일을 어리석게 읽을 때 시도하거나 발견 할 수있는 것. 이 답변이 작성되었을 때 의 답변 상태입니다 . 나중에 비 OP 가이 답변의 check과 같은 코드를 포함하도록 편집했습니다 "".

    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. [나중에 좋은 답변 으로 편집 ] 접근 방식 buffer[strcspn(buffer, "\n")] = 0;과 비교할 때 성능 이외 의 1 라이너에는 문제가 없습니다 strlen(). 트리밍 성능은 일반적으로 코드가 I / O를 수행 할 때 문제가되지 않습니다. CPU 시간의 블랙홀입니다. 다음 코드는 문자열 길이가 필요하거나 성능을 높이려면이 strlen()방법을 사용하십시오 . 그렇지 않으면 strcspn()훌륭한 대안입니다.


답변

모든 줄에 ‘\ 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';
}


답변

단일 ‘\ 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';
  }
}


답변

내 초보자 방법 😉 그것이 올바른지 알려주십시오. 내 모든 경우에 효과가있는 것 같습니다.

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