알고리즘 문제!! 풀어보기!!
Q
파일 이름을 선택할 때, 와일드 카드(Wild Card) 문자를 사용할 수 있는 기능은 많은 운영체제의 명령어에서 기본적으로 제공하고 있다.
자주 사용되는 wild card 문자에는 ‘*’와 ‘?’가 있다. *는 임의의 0개 이상의 인접한 문자열과 일치하게 되고, ?은 임의의 문자 하나와 일치하게 된다. 그 외 공백이 아닌 문자는 오직 그 자신과만 일치하게 된다.
예를 들어, 패턴 A?*?X는 파일 이름 ABCX, ABCDX, ABCDEX와 일치되지만, AX나 ABX와는 일치되지 않는다. 패턴 *X*는 X가 어디에나 위치한 파일 이름과 일치되지만, 패턴 ?X*의 경우는 적어도 두 개의 문자를 포함하며 두 번째 위치에 X가 존재하는 파일 이름과 일치한다. 패턴 X*X에서 일치하는 것들은 패턴 X**X에서도 같이 일치하게 된다.
와일드 카드(Wild Card) 문자 *와 ?을 포함하는 패턴 하나와 여러 개의 파일명이 주어질 때, 주어진 패턴과 일치하는 파일명을 모두 찾아 출력하는 프로그램을 작성하시오.
[입력 형식]
입력 파일의 이름은 INPUT.TXT이다. 첫째 줄에 패턴이 주어진다. 둘째 줄에는 파일명의 개수가 주어지고 세번째줄부터 파일명이 한 줄에 하나씩 입력된다. 패턴과 파일명의 길이는 모두 30을 넘지 않고, 파일명은 최대 100개가 주어진다. 파일명에는 영문 대소문자와 0부터 9까지의 숫자 문자로 구성되어 있다. 파일명의 첫 문자는 숫자 문자가 아니다. 영문 대소문자는 서로 구별된다. 즉, ‘A’와 ‘a’는 다르다.
[출력 형식]
출력 파일의 이름은 OUTPUT.TXT이다. 첫째 줄에 주어진 패턴과 일치하는 파일명의 수를 출력한다. 둘째 줄부터 마지막 줄까지 주어진 패턴과 일치하는 파일명을 한 줄에 하나씩 출력한다. 출력할 파일명은 아무 순서로나 해도 된다.
A
#include <stdio.h>
#include <conio.h>
#include <string.h>
char pattern[30] = {'\0', }; // 와일드 카드 값 (즉, 검색할 패턴)
char patternEnd[30] = {'\0', }; // 반대로 저장된 패턴
char data[100][30] = {'\0', }; // 비교할 문자열들
char dataCopy[30] = {'\0', }; // 임시로 복사해둔 문자열, data에서 비교된 문자가 패턴에 적합하면 result에 복사된다. data배열은 비교중에 데이터가 변경되므로, 변경되지 않은 원본을 따로 저장하는 역할을 한다.
char result[100][30] = {'\0', }; // 결과 문자열들
int patternCounter = 0; // 패턴의 카운터
int patternEndCounter = 0; // 패턴의 뒤쪽부터의 카운터
int dataEndCounter = 0; // 문자열의 뒤쪽부터의 카운터
int wordCounter = 0; // 파일로 부터 입력받은 파일의 개수
int resultCounter = 0; // 결과 문자열의 개수
void InputFile(); // 데이터 입력
void OutputFile(); // 결과 출력
void SetPatternEnd(); // 패턴을 patternEnd에 반대로 저장한다.
bool CompareBasicPattern(int point); // 패턴과 문자열을 비교한다. 문자, ?, * 비교
void main()
{
bool flagEnd = true, onStarSearch = false; // * 가 나타나면 검사 수행 체크
int patternPointer = 0; // 와일드 카드 위치, 문자를 검사할 때, 현재 검사하고 있는 문자의 위치를 저장한다.
int dataPointer=0; //문자열을 비교할때 위치, 문자열의 위치를 저장
int tempPattern = -1;
InputFile(); // 파일로부터 데이터 얻어오기
SetPatternEnd();
for(int i = 0; i < wordCounter; i++)
{
strcpy(dataCopy, data[i]); // 나중에 결과값에 올바른 문자열을 저장하기 위해 dataCopy에 원본 저장
dataEndCounter = strlen(data[i]) - 1; // 문자열의 길이를 가지고, dataEnd의 초기 위치 얻기
patternEndCounter = 0;
flagEnd = CompareBasicPattern(i); // 패턴과 문자열 비교
while(flagEnd == true)
{
if(pattern[patternPointer] != '*' && pattern[patternPointer] != '?' && pattern[patternPointer] != 0) // patter이 *,? 이 아니라면
{
if(onStarSearch == false) //'*'가 앞에 없을 경우
{
if(pattern[patternPointer] == data[i][dataPointer]) // 패턴과 문자열의 문자가 같다면
{
dataPointer++; // 문자열의 다음 문자로 이동
patternPointer++;// 패턴의 다음 문자로 이동
}
else // 같지 않다면
{
if(data[i][dataPointer] == '\0') // 문자열이 끝났다면 종료
break;
dataPointer++; // 문자열의 다음 포인터로 이동
if(tempPattern >= 0)
patternPointer = tempPattern;
else
break;
}
}
else // '*' 가 앞에 있을 경우
{
while(pattern[patternPointer] != data[i][dataPointer]) // 패턴과 문자열의 데이터가 같지 않다면
{
dataPointer++; // 문자열의 데이터만 포인터를 중가시킨다.
if(data[i][dataPointer] == '\0') // 문자열이 끝났다면 종료
break;
}
if(data[i][dataPointer] == '\0') // 문자열이 끝났다면 종료
break;
dataPointer++; // 문자열의 데이터와 패턴의 포인터를 모두 증가시킨다.
patternPointer++;
onStarSearch = false; // * 탐색 종료
}
}
else if(pattern[patternPointer] == '?') // 패턴에 ?가 있다면
{
if(data[i][dataPointer] == '\0') // 문자열이 끝났다면 종료
break;
else // 그렇지 않다면 문자열의 데이터와 패턴의 포인터를 모두 증가시킨다.
{
dataPointer++;
patternPointer++;
}
}
else if(pattern[patternPointer] == '*') // 패턴에 *가 있다면
{
onStarSearch = true; // * 검색모드를 true
tempPattern = patternPointer;
patternPointer++;
}
else if(pattern[patternPointer] == 0) // 패턴의 비교가 모두 끝났다면, 더이상 비교할 패턴의 문자가 없다면
{
if(onStarSearch != true) // * 검색중이 아니었다면, 패턴에 적합한 문자열 처리
{
if(data[i][dataPointer] == 0) // 데이터(data)의 문자열의 문자가 모두 소진되었다면
{
strcpy(result[resultCounter++], dataCopy); // 결과 리스트에 포함
break;
}
else // 결과 리스트에 포함시키지 않는다.
break;
}
else // * 검색 중이었다면
{
strcpy(result[resultCounter++], dataCopy); // 결과 리스트에 포함
break;
}
}
}
// 데이터 초기화
patternPointer = dataPointer = 0;
tempPattern = -1;
flagEnd = true;
onStarSearch = false;
}
OutputFile(); // 결과 출력
}
bool CompareBasicPattern(int point) // 기본적인 패턴 비교
{
while(patternEnd[patternEndCounter] != '\0') // 패턴(반대로 저장된)에 문자가 남아있다면
{
if(data[point][dataEndCounter] == patternEnd[patternEndCounter]) // 패턴(반대로 저장된)과 문자열의 문자가 같다면, 뒤에서부터 비교
{
dataEndCounter--;
patternEndCounter++;
}
else if(patternEnd[patternEndCounter] == '?') // 패턴(반대로 저장된)에 ?가 나왔다면
{
dataEndCounter--;
patternEndCounter++;
}
else
return false;
}
return true;
}
void SetPatternEnd() // 패턴을 반대로 저장
{
while(pattern[patternCounter] != '*') // 패턴의 문자중에서 '*'가 나올때까지 (pattern의 뒤에서부터 문자를 읽는다.)
{
patternEnd[patternEndCounter] = pattern[patternCounter]; // pattern의 뒤에서부터 읽은 문자를 patternEnd의 앞쪽부터 쓴다.
pattern[patternCounter] = '\0'; // pattern에서 읽은 데이터는 지운다.
patternCounter--; // 배열의 이동
patternEndCounter++;
}
}
void InputFile() // 파일로 부터 입력받기
{
FILE *fp; // 파일 포인터 개체
fp = fopen("Input.txt", "r"); // 파일 열기
fscanf(fp, "%s", pattern); // 패턴 문자열 얻어오기
fscanf(fp, "%d", &wordCounter); // 입력받은 문자열의 개수
patternCounter = strlen(pattern) - 1; // 패턴의 마지막 문자 위치를 patternCounter 에 준다.
for(int i = 0; i < wordCounter; i++) // 문자열을 읽어온다.
fscanf(fp, "%s", data[i]);
fclose(fp); // 파일 닫기
}
void OutputFile()
{
FILE *fp; // 파일 포인터 개체
fp = fopen("Output.txt", "w"); // Output.txt 파일을 쓰기 형식으로 열기
fprintf(fp, "%d\n", resultCounter); // 화면에 출력
printf("%d\n", resultCounter); // 파일에 출력
for(int i = 0; i < resultCounter; i++)
{
printf("%s\n", result[i]); // 화면에 출력
fprintf(fp, "%s\n", result[i]); // 파일에 출력
}
printf("결과값은 Output.txt 에 출력되었습니다.\n"); // 결과값 출력
fclose(fp);
}
학교다닐 때 짠거라 코드가 좀 초보티가 많이 날 수도 있습니다. ;;;
코드는 C 언어로 작성되었습니다. (Visual Studio 6.0 버전에서 컴파일)
'개발&컴퓨터 > 알고리즘' 카테고리의 다른 글
[알고리즘문제] 볼록 다각형의 교차 영역 (0) | 2015.05.30 |
---|---|
Texture Synthesis by Image Quilting 알고리즘 (Computer Graphics) (0) | 2015.05.18 |
[알고리즘문제] 숫자 대응 (0) | 2015.04.18 |
[알고리즘문제] 수열 추정 (0) | 2015.03.31 |
[소개] 알고리즘을 쉽게 이해하며 배워보기 (VisuAlgo.NET) (1) | 2015.03.15 |