Giken Dev
article thumbnail
반응형

https://www.acmicpc.net/problem/1152

 

1152번: 단어의 개수

첫 줄에 영어 대소문자와 띄어쓰기로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 띄어쓰기 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한

www.acmicpc.net

문제

영어 대소문자와 띄어쓰기만으로 이루어진 문자열이 주어진다. 이 문자열에는 몇 개의 단어가 있을까? 이를 구하는 프로그램을 작성하시오. 단, 한 단어가 여러 번 등장하면 등장한 횟수만큼 모두 세어야 한다.

입력

첫 줄에 영어 대소문자와 띄어쓰기로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 띄어쓰기 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한 문자열의 앞과 뒤에는 공백이 있을 수도 있다.

출력

첫째 줄에 단어의 개수를 출력한다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
int main() {
	char str[1000000];
	int num = 0;
	int was_space = 1;	//1: 바로 전 문자가 space이다.   
						//처음의 공백이 카운팅되는걸 방지하려고 1로 초기화
	scanf("%[^\n]", str);
	
	for (int i = 0; str[i] != '\0'; i++) {				
		if (isspace(str[i])) {		//공백일 때			
			was_space = 1;
		}							
		else {						//공백 아닐 때
			if (was_space == 1) {
				num++;
			}
			was_space = 0;
		}
	}

	printf("%d", num);
}

문제풀이

 

헤더에 ctype.h를 넣어주고 isspace()를 활용했습니다. for문에서 was_space라는 int형 변수로 str[i - 1]이 공백이었는지를 판단하게 했습니다.

이번 문제를 풀며 새롭게 안 사실인데, %s로 문자열을 받으면 이 문제를 죽어도 풀기 힘들 것입니다. 그래서 scanset을 활용하여 %[^\n]으로 입력을 받았습니다.      ^: 제외하라       [^\n]: \n 제외하고

기존의 %s는 문자열의 '\0'의 뒤로는 입력을 받지 않기 때문에, 공백 이전의 한 단어만 입력을 받을 수 있습니다.

비고

문자열에 관한 개념이 매우 다양하기 때문에 scanset을 포함한 개념들을 따로 공부를 해야할것 같습니다. 


스캔셋(Scanset)은 기본적으로 %s와 유사하지만 모든 문자열을 입력받는 것이 아니라 별도로 기술한 범위에 속하는 것들만 골라서 입력을 받는다는 점이 다릅니다. 그리고 그 범위에 속하지 않는 문자가 등장하는 지점에서 입력을 끝내버립니다. %s는 입력 구분을 의미하는 공백 문자를 처리할 수 없었지만 스캔셋을 이용하면 scanf()함수가 gets()함수처럼 작동하게 할 수도 잇습니다.

 

#include <stdio.h> int main(void) { char szBuffer[32] = { NULL }; scanf("%[A-Z]", szBuffer); puts(szBuffer); scanf("%s", szBuffer); puts(szBuffer); return 0; }

스캔셋은 %[]형식 문자로 기술합니다. 내부적으로 사용자가 입력한 문자열을 스캔셋을 근거로 구문 분석하고 걸러내어 조건에 맞는 문자들을 골라서 저장합니다. 그리고 조건에 맞지 않는 문자가 등장하면 더는 읽어 내지 않고 멈춥니다. 

예를들어 "TESTstring"이라고 입력했다면 "TEST"까지만 배열에 저장합니다. 그래서 실행결과는 TEST 후에 버퍼에 남아있는 string이 출력됩니다. 아래의 scanf()함수는 버퍼에 문자열이 남아있기때문에 입력을 받지 못하는 경우입니다. 

 

그리고 읽어내고 싶은 범위를 여럿 명시하고 싶다면 반점(,)을 이용하면 됩니다.

#include <stdio.h> int main(void) { char szBuffer[32] = { NULL }; scanf("%[^A-Z]", szBuffer); puts(szBuffer); scanf("%s", szBuffer); puts(szBuffer); return 0; }

가령 %[A-Z, a-z]라고 명시하면 영문 대문자와 소문자 모두가 범위로 지정됩니다. 만일 공백 문자를 삽입하여 %[ A-Z,a-z]라고 기술하면 공백 문자를 입력의 구분자로 사용하지 않고 일반 문자처럼 그냥 읽어내어 메모리에 저장해줍니다. 또한 ^기호를 이용하면 입력 범위가 아니라 입력받지 않을 범위를 지정할 수 있습니다. 

 

scanf()함수로 gets()함수처럼 사용할수 있다.

#include <stdio.h> int main(void) { char szBuffer[32] = { NULL }; scanf("%[^\n]%*c", szBuffer); puts(szBuffer); gets(szBuffer); puts(szBuffer); return 0; }

%[^\n]이 의미하는 것은 줄 바꿈 문자를 제외한 나머지 모든 문자를 의미합니다. 따라서 gets()함수처럼 공백 문자도 입력받을 수 있습니다. 그리고 이어서 %*c 형식 문자를 조합함으로써 입력 버퍼에 남을 줄 바꿈 문자를 제거함으로써 이후에 나오는 gets()함수에서 키보드로부터 입력을 받을 수 있습니다.

 

[ 출저 ] - 명강의로 완성하는 C 프로그래밍



출처: https://happyand930.tistory.com/20 [SoultoMind]

반응형
profile

Giken Dev

@기켄

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!