RiseOJ는 solved.ac와 제휴 관계가 없습니다. 티어 아이콘 © solved.ac. solved.ac
← 실버 IV

문자열 파싱

토큰 분리, 숫자 추출, 형식 있는 입력 처리.

문자열 Silver IV 실버 IV
선수 지식: 문자열 기초
1강 토큰 분리와 형식 있는 입력 다루기 공식

문자열 파싱이란?

파싱(parsing) 은 형식이 있는 문자열에서 의미 있는 조각(토큰)을 뽑아내는
일입니다. "3 + 4 * 2"에서 숫자와 연산자를 분리하거나, "2026-06-05"에서 연·월·
일을 떼어 내는 것이 모두 파싱입니다.

문제에서 입력이 단순한 정수 나열이 아니라 구분자·기호·단어가 섞인 형식으로
주어지면 파싱 능력이 필요합니다.


1. 가장 흔한 작업: 구분자로 자르기

공백이나 쉼표 같은 구분자(delimiter) 로 문자열을 토막 내는 것이 기본입니다.

"apple,banana,cherry"  --쉼표로 자르면-->  ["apple", "banana", "cherry"]

파이썬은 split이 매우 강력하고, C++은 stringstream이나 직접 순회로 처리합니다.


2. 공백 기준 토큰화

가장 자주 만나는 형식은 공백으로 나뉜 토큰입니다.

"GCC 13 cpp"  →  단어 "GCC", "cpp" 와 숫자 13

이때 단어와 숫자가 섞여 있으면, 잘라낸 토큰을 보고 숫자처럼 생겼으면 정수로
변환
하는 식으로 처리합니다.


3. 숫자만 뽑아내기

문장 속에 흩어진 숫자만 추출해야 할 때가 있습니다. 한 글자씩 보면서

  • 숫자('0'~'9')면 현재 숫자에 이어 붙이고,
  • 숫자가 아니면 지금까지 모은 숫자를 하나의 수로 확정한다.

이 "상태를 들고 한 글자씩 읽는" 패턴이 파싱의 핵심 기술입니다. 음수 부호나
소수점이 끼면 조건을 추가하면 됩니다.


4. 한 글자씩 읽는 상태 기계

복잡한 형식(예: 수식, 좌표 (3,4), 시각 12:30)은 현재 무엇을 읽는 중인지
상태로 들고 한 글자씩 처리하는 방식이 가장 견고합니다.

상태 글자가 숫자 글자가 기호
숫자 읽는 중 이어 붙임 숫자 확정, 기호 처리
기호 기다림 새 숫자 시작 기호 처리

이 사고법은 나중에 컴파일러·인터프리터의 토크나이저까지 그대로 이어집니다.


5. 자주 마주치는 함정

  • 줄 단위 입력 vs 토큰 단위 입력 섞임 — 정수를 cin >> n으로 읽은 뒤
    getline으로 줄을 읽으면, 남아 있던 줄바꿈이 빈 줄로 읽힙니다. 줄바꿈을
    먼저 비워 줘야 합니다.
  • 연속된 구분자"a,,b"처럼 빈 토큰이 생기는 경우를 어떻게 다룰지 정하세요.
  • 앞뒤 공백 — 입력 끝의 공백·줄바꿈을 제거(trim)해야 할 때가 많습니다.

정리

파싱은 "형식 있는 문자열 → 의미 있는 토큰"입니다. 구분자로 자르기, 숫자 추출,
한 글자씩 읽는 상태 기계 — 이 세 가지면 Silver 수준의 파싱은 대부분 해결됩니다.
다음 강의에서 구체적인 도구를 익힙니다.

2강 split·stringstream과 파싱 구현 공식

파싱 도구 손에 익히기

언어별 파싱 도구를 정리하고, 대표 작업들을 코드로 구현합니다.


1. 공백/구분자로 자르기

s = "apple banana cherry"
parts = s.split()             # 공백 기준 → ['apple', 'banana', 'cherry']
csv = "a,b,c".split(",")      # 쉼표 기준 → ['a', 'b', 'c']
nums = list(map(int, "3 4 5".split()))   # 정수 리스트
#include <sstream>
string s = "apple banana cherry";
stringstream ss(s);
string token;
while (ss >> token)           // 공백 기준으로 하나씩
    cout << token << '\n';

C++의 stringstream>>로 공백 토큰을, getline(ss, token, ',')로 임의
구분자 분리를 지원합니다.

stringstream ss("a,b,c");
string token;
while (getline(ss, token, ','))   // 쉼표로 자르기
    cout << token << '\n';

2. 문장 속 숫자 추출

string s = "x=12, y=-7";
long long num = 0; bool neg = false, in = false;
for (char c : s) {
    if (isdigit(c)) { num = num * 10 + (c - '0'); in = true; }
    else if (c == '-') neg = true;
    else if (in) {                     // 숫자가 끝났다
        cout << (neg ? -num : num) << '\n';
        num = 0; neg = false; in = false;
    } else neg = false;
}
if (in) cout << (neg ? -num : num) << '\n';   // 마지막 숫자
import re
s = "x=12, y=-7"
nums = list(map(int, re.findall(r'-?\d+', s)))   # [12, -7]

파이썬의 정규식 re.findall(r'-?\d+', s)은 음수 포함 모든 정수를 한 줄로
뽑아냅니다. 매우 자주 쓰는 관용구입니다.


3. cin과 getline 섞기 함정 해결

int n;
cin >> n;
cin.ignore();                 // 남은 줄바꿈 버리기 — 핵심!
string line;
getline(cin, line);           // 이제 제대로 한 줄 읽힘
import sys
input = sys.stdin.readline
n = int(input())
line = input().rstrip("\n")   # readline은 줄바꿈을 포함하므로 제거

C++에서 cin >> n 다음 getline을 부르기 전에 cin.ignore()로 남은 줄바꿈을
버리지 않으면, getline이 빈 줄을 읽어 버립니다.


4. 형식 있는 입력 파싱: 시각 "HH:MM"

h, m = map(int, "12:30".split(":"))
total_minutes = h * 60 + m
int h, m; char colon;
sscanf("12:30", "%d:%d", &h, &m);   // sscanf로 형식 지정 파싱

C++의 sscanf"%d:%d", "(%d,%d)"처럼 형식을 직접 지정해 한 번에 뜯어낼
수 있어 좌표·날짜·시각 파싱에 편리합니다.


5. 흔한 실수

  • cin >> ngetlinecin.ignore() 빠뜨리면 빈 줄을 읽음.
  • readline() 줄바꿈 포함 — 파이썬은 rstrip()으로 제거.
  • 빈 토큰split(",")"a,,b"에서 빈 문자열을 만듦. 필터링 여부 결정.
  • 숫자 추출 시 마지막 숫자 누락 — 반복이 끝난 뒤 마지막에 모은 숫자를 한 번 더
    확정해야 합니다.

6. 패턴 알아보기

  • "공백/쉼표로 나뉜 토큰" → split / stringstream.
  • "문장 속 숫자만" → 한 글자씩 또는 정규식.
  • "정해진 형식(좌표·시각)" → sscanf / split + 변환.
  • "줄 단위 처리" → getline / readline (줄바꿈 주의).
3강 실전 가이드 — 입력 형식이 곧 문제인 경우 공식

실전에서 파싱 문제 알아보기

파싱 문제는 알고리즘이 아니라 입력 형식과의 싸움입니다. 채점 데이터의
구석에 숨은 형식 예외를 미리 의심하는 것이 합격선입니다.


1. 출제 신호

  • 입력이 공백·쉼표·괄호가 섞인 자유 형식 — "이름,나이;이름,나이" 같은
    구분자 혼합.
  • 빈칸을 포함한 한 줄 전체를 읽어야 함 — 문장에서 단어 세기, 태그 처리.
  • 시각·날짜 형식 — "HH:MM:SS"를 읽어 초로 환산하는 류.
  • 명령어 스크립트를 한 줄씩 해석해 수행하는 인터프리터형 문제.
  • 입력 끝이 명시되지 않고 EOF까지 읽어야 하는 문제.

2. 풀이 결정 절차

  1. 구분자 목록을 적습니다 — 공백? 쉼표? 둘 다? 연속될 수 있나?
  2. 읽기 단위를 정합니다 — 토큰 단위(cin >>, split)인가, 줄 단위
    (getline, input())인가? 빈칸 포함 문자열이 있으면 줄 단위가 필수입니다.
  3. 변환과 검증을 분리합니다 — 토큰을 자른 뒤 숫자 변환, 범위 검사 순서로.
  4. 엣지 케이스를 나열합니다 — 빈 줄, 연속 구분자(빈 토큰), 앞뒤 공백,
    마지막 줄에 개행 없음.

3. 자주 하는 실수

  • cin >> 뒤의 getline이 빈 줄을 읽음. >>는 개행을 버퍼에 남기므로
    바로 getline하면 빈 문자열이 옵니다.
int n;
cin >> n;
cin.ignore();                  // 버퍼에 남은 '\n' 제거
string line;
getline(cin, line);            // 이제 진짜 첫 줄을 읽는다
  • 파이썬 split(' ')split()의 차이. split(' ')은 연속 공백에서
    빈 문자열을 만들지만, 인자 없는 split()은 연속 공백을 묶어 처리하고
    앞뒤 공백도 무시합니다. 단어 세기는 거의 항상 split()이 맞습니다.
  • '\r' 잔류. 채점 데이터가 Windows 개행(\r\n)이면 getline 결과
    끝에 \r이 붙어 비교가 실패합니다. line.strip()(파이썬) 또는 끝 문자
    검사(C++)로 제거하세요.
  • EOF 처리 누락. "입력이 끝날 때까지"는 C++은 while (cin >> x),
    파이썬은 for line in sys.stdin 패턴입니다. 줄 수를 가정하면 틀립니다.
  • stringstream 재사용. 같은 stringstream을 다시 쓰려면 ss.clear()
    ss.str(newLine)을 해야 합니다. clear()만으로는 내용이 안 바뀝니다.

4. 연습 방법

이 페이지 오른쪽의 추천 문제는 쉬운 것부터 어려운 것 순입니다. 단순
토큰 분리부터 시작해 구분자 혼합, 인터프리터형으로 단계가 올라갑니다.

제출 전에 자기만의 엣지 입력 4종(빈 줄·연속 구분자·앞뒤 공백·개행 없는
마지막 줄)을 만들어 직접 넣어 보는 습관을 들이세요. 3문제 이상 풀어
클리어하면 레이팅의 CLASS 보너스에 반영됩니다.