검색

2009-10-26 2 views
5

다음 코드는 하나 개의 문자 시간에 텍스트 파일을 읽고 표준 출력에 인쇄 :검색

#include <stdio.h> 

int main() 
{ 
    char file_to_open[] = "text_file.txt", ch; 
    FILE *file_ptr; 

    if((file_ptr = fopen(file_to_open, "r")) != NULL) 
    { 
     while((ch = fgetc(file_ptr)) != EOF) 
     { 
      putchar(ch); 
     } 
    } 
    else 
    { 
     printf("Could not open %s\n", file_to_open); 
     return 1; 
    } 
    return(0); 
} 

하지만 그 대신 인쇄의 표준 출력을 [putchar (CH)] 내가 원하는 파일에서 다른 텍스트 파일에 제공된 특정 문자열을 검색합니다. strings.txt 및 출력 매치 라인과

text_file.txt를 out.txt한다 :

 
1993 - 1999 Pentium 
1997 - 1999 Pentium II 
1999 - 2003 Pentium III 
1998 - 2009 Xeon 
2006 - 2009 Intel Core 2 

strings.txt을 : text_file.txt의 세 제 라인이 일치 할 경우에이

 
Nehalem 
AMD Athlon 
Pentium 

한다. C에서 파일 작업에 대한 연구를 해본 결과 fgetc [내 코드에서와 같이] 한 줄을 fgets과 한 줄, fread 한 줄로 읽을 수있는 것 같습니다. 내 상황에 완벽 할까?

+3

왜이 프로그램을 쓰고있다?! grep/awk/sed를 사용하십시오. –

+0

아니, 팀. 태그는 검색 용입니다. 아무도 그걸 찾지 않을거야. – GManNickG

+1

예, 표준 유닉스 도구로는 몇 초 만에이 문제를 해결할 수 있습니다. 그러나 이것은 C 파일 IO에 대한 더 깊은 이해를 얻는 것입니다. –

답변

7

나는 이것이 학습 연습이라고 가정하고 시작하기위한 장소를 찾고 있습니다. 그렇지 않으면 바퀴를 재발 명하면 안됩니다.

아래 코드는 무엇이 관련되어 있는지 알려주는 코드입니다. 이 파일은 검색 할 파일의 이름과 그 파일에서 검색 할 단일 인수를 지정할 수있게 해주는 프로그램입니다. 이 구문을 수정하여 문자열 배열에서 검색하고 해당 배열의 단어 중 하나라도 읽은 행에 나타나는지 확인하십시오.

찾고있는 주요 기능은 strstr입니다.

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

#ifdef DEBUG 
#define INITIAL_ALLOC 2 
#else 
#define INITIAL_ALLOC 512 
#endif 

char * 
read_line(FILE *fin) { 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    int bufsize = INITIAL_ALLOC; 
    char *line = malloc(bufsize); 

    if (!line) { 
     return NULL; 
    } 

    buffer = line; 

    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 

     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
      return line; 
     } 

     else { 
      bufsize = 2 * bufsize; 
      tmp = realloc(line, bufsize); 
      if (tmp) { 
       line = tmp; 
       buffer = line + read_chars; 
      } 
      else { 
       free(line); 
       return NULL; 
      } 
     } 
    } 
    return NULL; 
} 

int 
main(int argc, char *argv[]) { 
    FILE *fin; 
    char *line; 

    if (argc != 3) { 
     return EXIT_FAILURE; 
    } 

    fin = fopen(argv[1], "r"); 

    if (fin) { 
     while (line = read_line(fin)) { 
      if (strstr(line, argv[2])){ 
       fprintf(stdout, "%s\n", line); 
      } 
      free(line); 
     } 
    } 

    fclose(fin); 
    return 0; 
} 

샘플 출력 :

 
E:\Temp> searcher.exe searcher.c char 
char * 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    char *line = malloc(bufsize); 
    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 
     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
       buffer = line + read_chars; 
main(int argc, char *argv[]) { 
    char *line; 
+0

이것은 매우 흥미로운 것 같습니다. 당신은 정확하게 추측하고 있습니다, 이것은 저를위한 학습 운동이며, 제가 이전에 작업 한 요소들로 구성되어 있다는 것을 알 수 있습니다. 그래서이 코드를 완전히 이해할 수 있어야합니다. –

+0

나는 C 코드를 처음 접했지만 fgets 함수 호출로 전체 read_line 함수 호출을 대체하고 fgets가 '\ n'문자에서 멈추기 때문에 주 함수에서 char * 행을 임의로 큰 수로 할당했습니다. 아마도 read_line 함수의 의도 된 목적을 설명 할 수 있습니까? 거기에 많은 불필요한 코드가있는 것 같습니다. – anon58192932

+1

@advocate [얼마나 큰가?] (http://en.wikipedia.org/wiki/Buffer_overflow) 적당한 크기의 버퍼부터 시작하여 필요에 따라 계속 확장합니다. 누군가가 라인 엔딩이없는 스트림을 먹이면 버퍼가 너무 커져서 컴퓨터가 메모리를 소모하지 못하도록하는 또 다른 검사가 실제로 있어야합니다. 그러나 이것은 간단한 학습 과제였습니다. –

4

기억 : fgetc(), getc(), getchar() 모두 char이 아닌 정수를 반환합니다. 정수는 EOF 또는 유효한 문자 일 수 있지만 char 유형에서 지원하는 범위보다 하나 많은 값을 반환합니다.

당신은 'fgrep'명령 대리를 작성하는이 : (-)는 fgets를 사용

fgrep -f strings.txt text_file.txt > out.txt 

대신 읽기 문자

, 당신은 라인을 읽을 필요 할 것입니다. (gets() 함수는 존재하지 않습니다!)

코드를 들여 쓰기하고 return 0을 삽입했습니다. (C99은 main()의 끝에서 벗어나면 암시적인 'return 0;'을 수행하지만). 그러나 C99는 모든 함수에 대해 명시적인 반환 유형을 요구합니다. 그리고 'int'를 'int main()'에 추가합니다 (그러나 끝에 0을 반환하지 않는 C99 호환 변명은 사용할 수 없습니다). 오류 메시지는 표준 출력이 아닌 표준 오류에 기록되어야합니다.

아마도 문자열 목록에 동적 할당을 사용해야 할 것입니다. 단순한 검색은 'strstr()'을 적용하여 각 입력 행에서 필요한 문자열 각각을 검색합니다 (일치하는 항목을 발견하면 루프를 깨뜨려야하므로 여러 개의 일치 항목이있는 경우 반복되지 않습니다) 한 줄에).

더 정교한 검색은 어떤 문자를 무시할 수 있는지 미리 계산하므로 모든 문자열을 병렬로 검색 할 수 있으므로 loop-in-a-loop보다 빨리 텍스트를 건너 뛸 수 있습니다. 이는 Boyer-Moore 또는 Knuth-Morris-Pratt (이 추가 된 : 또는 여러 문자열을 병렬 검색하도록 설계된 Rabin-Karp)와 같은 검색 알고리즘의 수정 일 수 있습니다.

+0

개인적으로 필자는 문자를 버퍼링하는 기능을 선호합니다 ... fgets 만 사용하면 줄 길이에 임의의 제한이 있습니다. – asveikau

+0

@asveikau : 그 차이가 보이지 않습니까? 우리가 버퍼를 제공하는 fgets를 사용할 때 우리는 원하는 크기로 설정할 수 있습니다. 그리고 strings.txt의 줄이 버퍼보다 ​​길면 어쨌든 문제가 발생합니다 ... fgets를 사용하는 경우에도 버퍼 오버플로를 관리해야합니까? 그렇습니다. 실제로 유형이 지정되지 않은 버퍼를 사용하는 것보다 덜 명확합니다. – kriss

+0

fgets()는 주어진 버퍼 길이까지 읽습니다. 그것이 공간을 다 써 버릴 때까지 개행 문자를 만나지 않았다면 멈추어 반환한다. 따라서 마지막 문자가 개행 문자가 아니고 버퍼가 가득차면 여분의 문자를 넣기 위해 더 많은 공간 (재 할당?)을 찾을 수 있고 fgets()를 다시 호출 할 수 있습니다 (주의 깊게 - 끝난 곳에서 시작, 여분의 공간)을 확보하고 더 많은 라인을 확보하십시오. 그래서 네, 당신은 동적으로 할당 된 버퍼에 데이터를 얻기 위해 자신의 독자를 작성할 수 있습니다 - 또는 버퍼를 처리하는 동안 읽기를 할 fgets()를 사용합니다. –

2

블록 단위로 읽는 것이 항상 기본 파일 시스템에서 작동하기 때문에 항상 더 좋습니다.

따라서 블록 단위로 읽은 다음 버퍼에 단어가 표시되는지 확인하고 다른 버퍼가 가득 찬 지 확인하십시오. 검색 단어가 버퍼 경계에있을 경우 검색 누락을 방지하기 위해 이전 버퍼의 마지막 몇 문자를 새 버퍼에 다시 복사하는 것이주의해야합니다.

이 간단한 알고리즘으로는 충분하지 않다면 (아마도 여러분의 경우) 한 버퍼에 여러 하위 문자열을 동시에 검색하는 훨씬 더 복잡한 알고리즘이 있습니다. .

+0

fgetc()를 사용하면 stdio가 블록 및 버퍼 문자로 읽히는 것이 확실합니다 ... – asveikau

+0

true이지만 fgetc를 호출하는 것은 비용이 들며 입력을 문자열 (또는 여러 문자열)과 비교하려는 경우, 어딘가에 복사해야합니다. 전체 버퍼를 읽고 버퍼로 작업하는 것보다 비용이 훨씬 큽니다. Jonathan이 제안한대로 전체 라인을 읽는 것은 버퍼를 직접 읽는 데 드는 세부적인 사항을 관리하고 싶지 않은 경우 전체 버퍼를 읽는 대신 좋은 대안입니다. – kriss

2
cat strings.txt |while read x; do grep "$x" text_file.txt; done 
+1

'fgrep -f strings.txt text_file.txt> out.txt'을 사용하셨습니까? –

+0

네, 예,'fgrep -f strings.txt text_file.txt'. 더 많은 노출은 더 많은 옵션을 의미합니다. –

+0

감사합니다. 이를 위해 C 프로그램을 작성하는 것은 완전한 시간 낭비입니다. –

관련 문제