c언어 파일함수로 특정 문자 찾기

c언어 파일함수로 특정 문자 찾기

 

 

지난 포스팅(c언어 파일입출력 함수를 이용해서 파일의 단어수 체크하기)에서는 파일 함수를 이용해서 특정문자가 포함되어 있는 줄을 찾아서 출력하는 예제를 살펴 보았다. 예를들어 onec one time라는 문자가 있고 one을 찾으면 onec one time 노란색으로 표시된 두 문자가 one을 포함하고 있기 때문에 one을 포함하는 단어는 2개라고 출력했다.

 

이번에는 c언어 파일 함수를 이용해서 찾을려고 하는 문자와 일치하는 경우에만 카운터를 해서 일치하는 문자수와 해당 라인을 출력해주는 예제를 살펴보자. 이번에는 one 이라고 검색하면 onec one time 처럼 one 만 찾아서 일치하는 단어는 하나라고 표현해 준다.

 

 

예제

 

searchword.c

 

아래 소스를 보면 이전 포스팅과 다른 부분이 strtok() 함수 부분이다.

 

readByte = fgets(buf, sizeof(buf) , fdr); 

 

위 fgets 함수를 이용해서 파일을 내용 한줄을 읽어 와서 buf에 담는다.

 

그리고 char *ptr = strtok(buf, " "); 함수를 이용해서 읽은 한줄내용에서 " " 공백을 기준으로 자른다.

 

마지막으로 while문을 돌면서 공백을 기준으로 자른 ptr을, 찾을문자 searchword와 아래 함수를 이용해서 비교한다.

 

int ret = strcmp(searchword , ptr);

 

#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"
#include "fcntl.h"


int main(int argc, char * argv[]){
    
    //파일 기술자
    FILE *fdr;
    
    //단어수
    unsigned int wordCount = 0;
    
    //라인 수
    unsigned int lineNumber = 0;
    
    //찾을 문자열
    char *searchword;
    
    //파일에서 읽을 바이트
    char buf[1024];
    char *readByte;
    
    char *fileName;
    
    if (argc != 3) {
        perror("인자 개수를 확인해 주세요. : ./searchfile filename searchword\n");
        exit(0);
    }
    
    //파일 이름
    fileName = argv[1];
    
    //찾을 문자열
    searchword = argv[2];
    
    
    //access() 함수는 프로세스가 지정한 파일이 존재하는지, 읽거나 쓰거나 실행이 가능한 지를 확인하는 함수
    //파일 접근가능 체크 - 존재 : 0, 존재안함 : -1
    int resultNum = access(fileName , F_OK);
    
    printf("접근 체크 결과 : %d\n" , resultNum);
    
    
    if (resultNum == -1) {
        
        //오류 출력함수
        perror("파일 접근 실패\n");
        
        exit(0);
    }
    
    //파일 기술자 열기
    fdr =  fopen(fileName , "r");
    
    if (fdr == NULL) {

        perror("파일 열기 실패\n");
        
        exit(0);
    }

    //파일의 끝이면 1, 끝이 아니면 0을 반환
    while (feof(fdr) == 0) {
        
        //라인 수 증가
        lineNumber += 1;
        
        //한줄읽기
        readByte = fgets(buf, sizeof(buf) , fdr);
        
        //복사를 위한 임시 문자열
        char *tempStr = malloc(sizeof(char) * 1024);
        
        //읽은 한줄을 복사 =>  tempStr
        strcpy(tempStr , readByte);
        
        //읽은 한 줄을 " " 기준으로 하나씩 자르기
        char *ptr = strtok(buf, " ");
        
        
        while (ptr != NULL) {
            
            //printf("자른 문자열 출력 : %s \n" , ptr);
            
            //두 문자열이 같은지 비교. 같으면  0
            //참고 : https://dojang.io/mod/page/view.php?id=346
            int ret = strcmp(searchword , ptr);
            
            //두 문자열이 같다.
            if (ret == 0) {
                //찾은 단어수 + 1
                wordCount += 1;
                
                printf("%d line : %s \n" ,lineNumber,  tempStr);
            }
            
            ptr = strtok(NULL, " "); //다음 문자열을 잘라서 포인터를 반환
  
        }
        
        //위에서 할당한 포인터 문자열 해제
        free(tempStr);
        
    }
    
    printf("** 파일 %s 에서 찾은 %s 단어 수 총 %d 개\n" , fileName, searchword , wordCount);
    
    
    //파일 닫기
    int closeResult = fclose(fdr);
    printf("파일 닫기 체크 : %d \n" , closeResult );
    
    //파일 닫기 체크
    if(closeResult < 0){
        perror("파일 닫기 실패");
        exit(0);
    }
    
    return 0;
    
}

 

실행결과

 

아래 명령어로 log 파일에서 one이라는 단어를 찾았다. 정확히 one 이라는 단어가 있는 라인만 성공적으로 출력되었다.

 

 ./searchword.o log one
접근 체크 결과 : 0
8 line : In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.
 
18 line : In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.
 
27 line : In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.
 
36 line : In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation. 
** 파일 log 에서 찾은 one 단어 수 총 4 개
파일 닫기 체크 : 0 

 

log 파일 내용

더보기

"(I chose) the ones that would be ones, perhaps ones enigmatic or ambiguous, long lasting, and thought-provoking," 
he said over the phone. Since beginning the project in 2018, Mermelstein has amassed around 1,200 images, according to his estimates.

And while ones to a few ones lines, the texts are enough to 
fabricate entire stories based on the information in each shot: A pair of hands and a snippet 
of conversation on a screen tell stories of lovers arguing with unfiltered haphazard thoughts; 
friends sharing pregnancy announcements; and former flings asking to just be friends. 
In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.


"(I chose) the ones that would be ones, perhaps even enigmatic or ambiguous, long lasting, and thought-provoking," 
he said over the phone. Since beginning the project in 2018, Mermelstein has amassed around 1,200 images, according to his estimates.

And while limited to a few ones lines, the texts are ones to 
fabricate entire stories based on the information in each shot: A pair of hands and a snippet 
of conversation on a screen tell stories of lovers arguing with unfiltered haphazard thoughts; 
friends sharing pregnancy announcements; and former flings asking to just be friends. 
In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.

"(I chose) the ones that would be memorable, ones even enigmatic or ambiguous, long lasting, and thought-provoking," 
he said over the phone. Since beginning the project in 2018, Mermelstein has amassed around 1,200 images, according to his estimates.

And while limited to a few anonymous lines, the texts are enough to 
fabricate entire stories based on the information in each shot: A pair of hands and a snippet 
of conversation on a screen tell stories of lovers arguing with unfiltered haphazard thoughts; 
friends sharing pregnancy announcements; and former flings asking to just be friends. 
In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.

"(I chose) the ones that would be memorable, perhaps even enigmatic or ambiguous, long lasting, and thought-provoking," 
he said over the phone. Since beginning the project in 2018, Mermelstein has amassed around 1,200 images, according to his estimates.

And while limited to a few anonymous lines, the texts are enough to 
fabricate entire stories based on the information in each shot: A pair of hands and a snippet 
of conversation on a screen tell stories of lovers arguing with unfiltered haphazard thoughts; 
friends sharing pregnancy announcements; and former flings asking to just be friends. 
In one image, a person sends an extensive mea culpa after experiencing an Ayahuasca-induced revelation.

 

 

참고

strtok 함수 예제

 

#define _CRT_SECURE_NO_WARNINGS    // strtok 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h>    // strtok 함수가 선언된 헤더 파일

int main()
{
    char s1[30] = "The Little Prince";      // 크기가 30인 char형 배열을 선언하고 문자열 할당

    char *ptr = strtok(s1, " ");        // " " 공백 문자를 기준으로 문자열을 자름, 포인터 반환

    while (ptr != NULL)                  // 자른 문자열이 나오지 않을 때까지 반복
    {
        printf("%s\n", ptr);            // 자른 문자열 출력
        ptr = strtok(NULL, " ");        // 다음 문자열을 잘라서 포인터를 반환
    }

    return 0;
}


 

포인터에 문자열 리터럴이 있으면 읽기 전용이라 수정할 수 없다.

 

다음과 같이 문자열 포인터에 문자열 리터럴이 들어있어서 읽기 전용인 상태라면 strtok 함수를 사용할 수 없다.

 

 char *s1 = "The Little Prince";   // 포인터에 문자열 리터럴 "The Little Prince"의 주소 저장

 

 char *ptr = strtok(s1, " ");      // 실행 에러

 

 ... 생략...

 

 실행 결과

 0xC0000005: 0x013A585D 위치를 기록하는 동안 액세스 위반이 발생.

 문자열 포인터에 문자열 리터럴을 할당하는 대신 동적 메모리를 할당하고, 문자열을 복사하면 이 문제를 해결할 수 있다.

 

 char *s1 = malloc(sizeof(char) * 30);    // char 30개 크기만큼 동적 메모리 할당

 strcpy(s1, "The Little Prince"); // s1에 문자열 복사

 

 ... 생략

 

 free(s1);

 

 

 

참고 

 

https://dojang.io/mod/page/view.php?id=756

https://dojang.io/mod/page/view.php?id=358

https://dojang.io/mod/page/view.php?id=376

https://blockdmask.tistory.com/382