본문으로 건너뛰기

단원 연습 문제

자바스크립트 목차문자열 다루기문제 12개

3단원 '문자열 다루기'의 세 레슨에서 9문제를 내고, 1~2단원에서 3문제를 섞었습니다. 앞 단원 문제가 어느 레슨인지는 정답을 펼치면 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 줄 수를 알려 주지 않는 문제는 마지막 줄까지 다 씁니다. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.

한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 30~40분), 끝의 만들어 보기 둘은 컴퓨터에서 Node로 직접 돌려 봅니다. 이 단원을 건너뛰어도 되는지 보려면 문제 1 · 4 · 5 · 6 · 9 다섯을 먼저 풀어 보세요(약 15분). 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다. 힌트를 펴고 맞힌 문제나 짐작으로 고른 문제는 틀린 것으로 치고 그 레슨을 봅니다. 모두 맞으면 이 단원 레슨은 건너뛰고, 틀린 문제가 있으면 그 정답 끝의 레슨만 봅니다. 파이썬을 배웠다면 파이썬과 달라지는 곳이 이 다섯에 들어 있습니다(정답의 '파이썬에서는' 줄). 끝의 만들어 보기 둘은 골라서 풉니다.

끝의 두 문제는 프로그램을 직접 만들어 봅니다. 컴퓨터가 있으면 저장해 돌려 맞춰 보고, 폰으로만 본다면 문제에 적힌 값으로 내 코드를 한 줄씩 따라가 나와야 할 화면과 맞춰 봅니다. 실행 결과는 모두 Node 26으로 돌린 것입니다.

문제 1

카페 메뉴판에 띄울 문구를 만듭니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.

const item = '녹차';
console.log(`${item} 한 잔`);
console.log(`{item} 한 잔`);
console.log('${item} 한 잔');
힌트

2~4번 줄은 문자열을 감싼 기호와 중괄호 앞의 글자만 다릅니다. 줄마다 견주어 보세요.

정답
실행 결과
녹차 한 잔
{item} 한 잔
${item} 한 잔
  • 2번 줄: 백틱 안의 ${item} 자리에 item이 붙은 '녹차'가 들어갑니다.
  • 3번 줄: 백틱이지만 $가 없어 {item}은 쓴 글자 그대로입니다.
  • 4번 줄: 작은따옴표 문자열이라 ${item}도 쓴 글자 그대로입니다.

흔한 오답은 셋째 줄의 녹차 한 잔입니다. ${}로 감싸기만 하면 값이 들어간다고 본 것입니다. 자리를 값으로 채우는 것은 백틱으로 감싼 문자열뿐입니다. 둘째 줄을 녹차 한 잔으로 쓰면 중괄호만으로 값이 들어간다고 본 것입니다.

파이썬에서는 f'{item} 한 잔'처럼 중괄호만 씁니다 — 자바스크립트는 백틱 안에서 $까지 붙인 ${item}만 값으로 채웁니다.

다시 볼 레슨: 템플릿 문자열로 출력 꾸미기

문제 2

같은 주문을 세 가지 꼴로 찍습니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.

const item = '라테';
const qty = 2;
console.log(item, qty, '잔');
console.log(item + qty + '잔');
console.log(`${item} ${qty}잔`);
힌트

줄마다 빈칸이 어디서 생기는지 보세요. 쉼표 · + · 템플릿의 빈칸이 저마다 다릅니다.

정답
실행 결과
라테 2 잔
라테2잔
라테 2잔
  • 3번 줄: console.log는 쉼표로 나눈 값 사이마다 빈칸을 하나씩 넣습니다.
  • 4번 줄: +는 빈칸 없이 이어 붙입니다. '라테'에 2를 글자로 이어 '라테2'가 되고, '잔'을 이어 '라테2잔'입니다.
  • 5번 줄: 템플릿에 쓴 빈칸은 ${item}과 ${qty} 사이의 하나뿐입니다.

흔한 오답은 첫 줄의 라테 2잔입니다. 쉼표로 넘긴 값은 붙어서 찍힌다고 본 것입니다. 둘째 줄을 라테 2 잔으로 쓰면 +도 빈칸을 넣는다고 본 것입니다.

다시 볼 레슨: console.log로 출력하기 · 문자열 잇기와 길이 · 템플릿 문자열로 출력 꾸미기

문제 3

주문 앱에서 잔 수가 글 '3'으로 들어왔습니다. 커피는 한 잔 4000원이고, 쿠키 12개를 잔마다 똑같이 나눠 줍니다. 무엇이 찍힐까요? 세 줄을 글자 그대로 쓰세요.

const cups = '3';
console.log(`${cups * 4000}원`);
console.log(`${cups + 1}잔`);
console.log(`${12 / cups}개씩`);
힌트

${} 안의 식을 먼저 값 하나로 계산합니다. 줄마다 기호가 글자 '3'을 어떻게 다루는지 보세요.

정답
실행 결과
12000원
31잔
4개씩
  • 2번 줄: *는 글자 '3'을 수 3으로 바꿔 곱해 12000이고, 그 값이 자리에 들어갑니다.
  • 3번 줄: +의 한쪽이 글자라 1을 글자로 바꿔 이어 '31'입니다.
  • 4번 줄: /도 '3'을 수로 바꿔 12를 3으로 나눕니다. 수는 한 종류라 나누어떨어지면 4입니다.

흔한 오답은 둘째 줄의 4잔입니다. 글자 '3'도 수처럼 더한다고 본 것입니다(문자열과 수를 가리지 않는 생각). 잔 수를 더하려면 Number(cups) + 1처럼 먼저 수를 만듭니다.

파이썬에서는 '3' * 4000이 글자를 4000번 되풀이하고 12 / 3이 4.0 — 자바스크립트는 *가 글자를 수로 바꿔 12000이고, 수는 한 종류라 4입니다.

다시 볼 레슨: 수·글자·불리언과 typeof · 사칙 계산과 나머지

문제 4

영화 시작 시각 '18:30'에서 시와 분을 꺼냅니다. 무엇이 찍힐까요? 마지막 줄까지 글자 그대로 쓰세요.

const time = '18:30';
console.log(time.slice(0, 2));
console.log(time.slice(3, 10));
console.log(time[5]);
console.log(time.length);
힌트

'18:30'의 글자마다 자리 번호를 0부터 적어 보세요.

정답

모두 네 줄입니다.

실행 결과
18
30
undefined
5
  • 2번 줄: slice(0, 2)는 0번부터 2번 자리 바로 앞까지라 '18'입니다.
  • 3번 줄: 끝 번호 10은 글자 수를 넘지만, 자르기는 있는 글자까지만 꺼내 '30'입니다.
  • 4번 줄: 다섯 글자의 번호는 0~4뿐이라 5번 자리는 없습니다. 오류 없이 undefined입니다.
  • 5번 줄: 숫자 넷과 콜론 하나라 5글자입니다.

흔한 오답은 첫 줄의 18:입니다. 자르기에 끝 번호의 글자도 든다고 본 것입니다(끝도 든다는 생각). 셋째 줄이나 둘째 줄에서 오류로 멈춘다고 쓰면 없는 자리를 꺼내면 바로 오류가 난다고 본 것입니다(없으면 오류라는 생각). 없는 자리는 undefined이고, 자르기는 범위를 넘어도 있는 글자까지만 꺼냅니다.

다시 볼 레슨: 인덱스와 자르기

문제 5

택배 송장 번호의 맨 끝 글자는 검사 숫자입니다. 번호가 '4721-0938-5'이면 검사 5가 찍혀야 합니다. 번호의 길이는 택배마다 달라, 1번 줄을 '31-77-8'로 바꾸면 검사 8이 찍혀야 합니다. 빈칸을 채우세요.

const code = '4721-0938-5';
const check = ____;
console.log(`검사 ${check}`);
힌트

길이가 달라도 늘 맨 끝 글자를 꺼내야 합니다. 뒤에서 세는 방법을 떠올려 보세요.

정답

code.at(-1)입니다.

const code = '4721-0938-5';
const check = code.at(-1);
console.log(`검사 ${check}`);
실행 결과
검사 5

at(-1)은 뒤에서 첫째 글자를 꺼냅니다. '31-77-8'로 바꾸면 '8'을 꺼내 검사 8이 찍힙니다.

  • 다르게 써도 되는 곳: 마지막 번호는 늘 글자 수 − 1이라 code[code.length - 1]⁠도 맞고, 뒤에서 한 글자를 자르는 code.slice(-1)도 맞습니다.
  • code[10]은 '4721-0938-5'에서는 '5'를 꺼내지만, '31-77-8'에서는 10번 자리가 없어 검사 undefined가 찍힙니다. 번호를 직접 쓰면 길이가 바뀔 때 갈립니다.

흔한 오답은 code[-1]입니다. 대괄호에 음수를 넣으면 뒤에서 센다고 본 것입니다. -1이라는 자리는 없어 검사 undefined가 찍힙니다. code[code.length]도 마지막 번호보다 하나 커서 undefined입니다.

파이썬에서는 code[-1]이 끝 글자 — 자바스크립트는 undefined이고, 끝 글자는 code.at(-1)입니다.

다시 볼 레슨: 인덱스와 자르기

문제 6

여행 사진에 단 해시태그에서 '#'를 지웁니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

let tag = '#jeju #sea';
tag.toUpperCase();
tag = tag.replace('#', '');
console.log(tag);
tag = tag.replaceAll('#', '');
console.log(tag, tag.length);
힌트

2번 줄부터 줄마다 이름 tag가 붙은 값을 적어 보세요.

힌트 둘

메서드 줄마다 만든 새 값에 이름 tag가 다시 붙는지 보세요.

정답
실행 결과
jeju #sea
jeju sea 8
  • 2번 줄: 대문자 새 값 '#JEJU #SEA'를 만들지만 아무 이름도 붙지 않아 버려집니다. tag는 그대로 '#jeju #sea'에 붙어 있습니다.
  • 3·4번 줄: replace()는 처음 찾은 '#' 하나만 지운 새 값 'jeju #sea'를 만들고, tag를 그 값에 다시 붙입니다. 4번 줄이 그 값을 찍습니다.
  • 5·6번 줄: replaceAll()이 남은 '#'까지 모두 지운 'jeju sea'에 tag를 다시 붙이고, 그 값과 글자 수 8을 빈칸 하나로 이어 찍습니다. 글자 일곱과 빈칸 하나입니다.

흔한 오답은 첫 줄의 JEJU #SEA입니다. 메서드를 부르기만 하면 그 문자열이 바뀐다고 본 것입니다. 새 값을 쓰려면 이름을 다시 붙입니다(규칙 3). 첫 줄을 jeju sea로 쓰면 replace()도 모두 바꾼다고 본 것입니다.

다시 볼 레슨: 문자열 메서드

문제 7

라테 주문 문구를 만든 뒤 잔 수가 늘었습니다. 무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

let cups = 2;
const order = `라테 ${cups}잔`;
cups = cups + 3;
console.log(order);
console.log(`라테 ${cups}잔`);
힌트

2번 줄의 템플릿 문자열이 언제 값 하나가 되는지 보세요.

정답
실행 결과
라테 2잔
라테 5잔
  • 2번 줄: 템플릿 문자열은 이 줄이 실행되는 순간 그때의 cups 2를 넣어 '라테 2잔'이라는 문자열 하나가 되고, order가 그 값에 붙습니다.
  • 3번 줄: cups만 새 값 5에 다시 붙습니다. order는 다시 계산되지 않습니다.
  • 4·5번 줄: order가 붙은 '라테 2잔'을 찍고, 5번 줄의 템플릿은 지금의 cups 5로 새로 만들어 '라테 5잔'을 찍습니다.

흔한 오답은 첫 줄의 라테 5잔입니다. 2번 줄이 ${cups} 자리를 저장해 두었다가 찍을 때 다시 채운다고 본 것입니다(식이 저장된다는 생각). 오른쪽은 대입하는 그때 한 번 계산하고, 이름은 그 값에 붙습니다(규칙 2).

다시 볼 레슨: 변수: let으로 이름 붙이기 · 템플릿 문자열로 출력 꾸미기

문제 8

카페 회원 이름의 첫 글자를 대문자로 바꾸려 합니다. 이 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

let name = 'mina';
console.log(name[0]);
name[0] = 'M';
console.log(name);
  • ① m · Mina를 차례로 찍는다
  • ② m을 찍은 뒤 3번 줄에서 TypeError로 멈춘다
  • ③ m · mina를 찍는다. 3번 줄은 오류 없이 지나가고 아무것도 바뀌지 않는다
힌트

3번 줄은 문자열의 한 칸에 대입합니다. 문자열 값을 그 자리에서 바꿀 수 있는지 떠올려 보세요.

정답

② — 실행 결과는 이렇습니다.

실행 결과
mmain.js:3name[0] = 'M';        ^ TypeError: Cannot assign to read only property '0' of string 'mina'    at main.js:3:9

2번 줄은 0번 자리의 'm'을 찍습니다. 3번 줄은 문자열의 0번 칸에 대입하려 하는데, 문자열은 한 번 만들면 바꿀 수 없는 값이라 TypeError로 멈춥니다. 설명은 '문자열 mina의 읽기 전용 속성 0에 대입할 수 없다'는 뜻입니다. 실행 중 오류라 앞에서 찍은 m은 남고 4번 줄은 실행되지 않습니다.

첫 글자를 바꾼 문자열이 필요하면 새 문자열을 만들어 이름을 다시 붙입니다. name = 'M' + name.slice(1);⁠이면 name이 'Mina'에 붙습니다.

  • ① 문자열의 한 칸을 그 자리에서 바꿀 수 있다고 봤습니다. 문자열 메서드가 새 값을 돌려주는 것과 같은 까닭으로, 문자열은 바뀌지 않습니다.
  • ③ 바꿀 수 없는 칸에 대입하면 조용히 무시된다고 봤습니다. 이 과목의 설정(모듈)에서는 오류로 멈춥니다. 옛 방식으로 돌리면 ③처럼 지나가니, 내 컴퓨터에서 이렇게 찍힌다면 설정 확인 줄부터 봅니다.

다시 볼 레슨: 문자열 메서드 · 오류 메시지 읽기

문제 9

하고 싶은 일마다 쓸 메서드 이름을 하나씩 쓰세요. 넷 다 쓴 뒤 정답을 펼치세요.

  • (가) 문자열 앞뒤의 빈칸을 뗀다
  • (나) 문자열의 뒤에서 첫째 글자를 꺼낸다
  • (다) 어떤 글자가 들어 있는지 참·거짓으로 알아본다
  • (라) 찾은 글자를 모두 다른 글자로 바꾼다
힌트

넷 다 문자열 뒤에 점을 찍고 괄호를 붙여 부르는 메서드입니다.

정답

받는 답: (가) trim · (나) at · (다) includes · (라) replaceAll

  • 같은 답으로 치는 꼴: 괄호까지 붙인 trim() · includes(), 값까지 넣어 쓴 s.at(-1) · s.replaceAll('-', ''). (나)에 slice(s.slice(-1))를 써도 맞습니다 — 끝 글자 하나를 잘라 꺼냅니다.
  • 틀리는 꼴 s[-1] — (나)에: 대괄호의 음수는 뒤에서 세지 않아 undefined입니다.
  • 틀리는 꼴 replace — (라)에: 처음 찾은 하나만 바꿉니다.
  • 틀리는 꼴 strip — (가)에: 자바스크립트 문자열에 없는 메서드라 TypeError로 멈춥니다(s.strip is not a function).
  • 틀리는 꼴 in — (다)에: 문자열에 쓰면 TypeError로 멈춥니다(Cannot use 'in' operator).

파이썬에서는 s.strip() · s[-1] · 'a' in s를 쓰고 s.replace()가 모두 바꿉니다 — 자바스크립트는 s.trim() · s.at(-1) · s.includes('a') · s.replaceAll()이고, replace()는 처음 하나만 바꿉니다.

다시 볼 레슨: 문자열 메서드 · 인덱스와 자르기

문제 10

메뉴 이름의 마지막 글자를 대문자로 바꿔 찍으려 했더니 아래처럼 멈췄습니다. 몇 번 줄의 무엇을 고쳐야 할까요? 고친 줄을 쓰세요.

const s = 'latte';
let last = s[s.length];
last = last.toUpperCase();
console.log(last);
실행 결과
main.js:3last = last.toUpperCase();            ^ TypeError: Cannot read properties of undefined (reading 'toUpperCase')    at main.js:3:13
힌트

…Error: 줄은 무엇에서 toUpperCase를 읽으려 했다고 하나요? 그 값을 만든 줄을 찾아봅니다.

정답

2번 줄을 let last = s.at(-1);로 고칩니다.

const s = 'latte';
let last = s.at(-1);
last = last.toUpperCase();
console.log(last);
실행 결과
E

오류는 3번 줄에서 났지만 까닭은 2번 줄에 있습니다. 'latte'는 다섯 글자라 번호가 0~4이고, s[s.length]는 없는 5번 자리를 꺼내 오류 없이 undefined를 줍니다. last가 그 undefined에 붙어, 3번 줄에서 undefined의 toUpperCase를 읽으려다 멈췄습니다. …Error: 줄의 'undefined의 속성을 읽을 수 없다'가 그 값을 만든 앞줄로 올라가라는 신호입니다.

  • 다르게 고쳐도 되는 곳: s[s.length - 1]도 마지막 4번 자리라 E가 찍힙니다.
  • 흔한 오답은 2번 줄을 s[-1]로 고치는 것입니다. 대괄호의 음수도 없는 자리라 여전히 undefined이고, 3번 줄에서 같은 오류로 멈춥니다. 3번 줄을 고치려는 것도 흔합니다. 3번 줄은 받은 값을 쓸 뿐이고, 틀린 값은 2번 줄에서 생겼습니다. 없는 자리를 꺼내는 줄은 멈추지 않고, 그 값을 쓰는 줄에서야 오류가 드러납니다(없으면 오류라는 생각).

다시 볼 레슨: 인덱스와 자르기 · 오류 메시지 읽기

문제 11 (만들어 보기)

영수증에 찍을 쿠폰 코드 가리개를 만들어 봅니다. 손님이 친 코드는 앞뒤에 빈칸이 끼고 소문자로 들어옵니다. 빈칸을 떼고 대문자로 바꾼 뒤, 가운데 네 자리만 별로 가려 찍습니다. ' fl-2026-1015 '이면 이렇게 나와야 합니다.

쿠폰 FL-****-1015

아래 뼈대의 주석 넷(2~5) 아래를 채우세요. 다 쓰면 1번 줄의 코드를 ' sm-1999-0007 '로 바꿔 따라가 봅니다. 쿠폰 SM-****-0007이 나와야 합니다.

// 1. 글 받기
let key = ' fl-2026-1015 ';
// 2. 다듬기
// 3. 앞뒤 자르기
// 4. 가려 잇기
// 5. 찍기
힌트

주석 넷마다 그 아래에서 할 일을 말로 한 줄씩 먼저 적어 보세요. 자를 자리는 다듬은 코드의 글자마다 번호를 적어 셉니다.

힌트 둘

'2. 다듬기'는 메서드 둘을 차례로 부르고, 그때마다 key를 새 값에 다시 붙입니다. 다듬은 코드에서 앞은 세 글자, 뒤는 다섯 글자를 잘라 그 사이에 '****'를 끼웁니다.

정답

모범 답입니다.

// 1. 글 받기
let key = ' fl-2026-1015 ';
// 2. 다듬기
key = key.trim();
key = key.toUpperCase();
// 3. 앞뒤 자르기
const head = key.slice(0, 3);
const tail = key.slice(-5);
// 4. 가려 잇기
let out = head + '****';
out = out + tail;
// 5. 찍기
console.log(`쿠폰 ${out}`);
실행 결과
쿠폰 FL-****-1015

' sm-1999-0007 '이면 key는 'SM-1999-0007'에 붙고, head는 'SM-', tail은 '-0007'입니다.

  • 다르게 써도 되는 곳: '4. 가려 잇기'를 head + '****' + tail 한 줄로 이어도 되고, 템플릿으로 ${head}****${tail}처럼 써도 됩니다. 뒤 다섯 글자는 key.slice(7)로 잘라도 됩니다. 이름은 달라도 됩니다.
  • 찍은 화면이 위와 같고 둘째 시험 값(' sm-1999-0007 ')도 맞으면 맞습니다. 둘째 값에서 FL-가 찍힌다면 앞 글자를 손으로 적은 것입니다.
  • 흔한 오답 하나는 key.trim();처럼 메서드를 부르기만 하는 것입니다. 빈칸을 뗀 새 값이 버려져, 자르는 자리가 한 칸씩 밀립니다. 빈칸이 보이게 앞뒤에 대괄호를 붙여 찍으면 이렇습니다.
let key = ' fl-2026-1015 ';
key.trim();
key = key.toUpperCase();
const head = key.slice(0, 3);
const tail = key.slice(-5);
let out = head + '****';
out = out + tail;
console.log(`[${out}]`);
실행 결과
[ FL****1015 ]
  • 다른 흔한 오답은 앞을 slice(0, 2)로 자르는 것입니다. 끝 번호의 글자가 들지 않아 쿠폰 FL****-1015가 찍힙니다(끝도 든다는 생각).

다시 볼 레슨: 문자열 메서드 · 인덱스와 자르기 · 템플릿 문자열로 출력 꾸미기

문제 12 (만들어 보기)

이번에는 빈 데서 씁니다. 카페 계산대 기계에서 오전 매출과 오후 매출이 글로 들어옵니다. 하루 매출과, 하루 매출 가운데 오전 매출이 몇 %인지 소수 첫째 자리까지 찍는 프로그램을 쓰세요. 오전 '84000', 오후 '126500'이면 이렇게 나와야 합니다.

하루 210500원
오전 39.9%

다 쓰면 두 글을 '50000'과 '50000'으로 바꿔 따라가 봅니다. 하루 100000원과 오전 50.0%가 나와야 합니다.

힌트

하위 목표 넷의 주석(1. 글 받기 · 2. 수로 바꾸기 · 3. 계산하기 · 4. 찍기)을 먼저 쓰고, 그 아래를 채웁니다.

정답

모범 답입니다.

// 1. 글 받기
let am = '84000';
let pm = '126500';
// 2. 수로 바꾸기
am = Number(am);
pm = Number(pm);
// 3. 계산하기
const sum = am + pm;
const rate = am / sum * 100;
// 4. 찍기
const text = rate.toFixed(1);
console.log(`하루 ${sum}원`);
console.log(`오전 ${text}%`);
실행 결과
하루 210500원
오전 39.9%

'50000' 둘이면 sum은 100000, rate는 50이고, toFixed(1)이 '50.0'을 만듭니다.

  • 다르게 써도 되는 곳: 합계 줄에서 Number(am) + Number(pm)⁠으로 바로 더해도 되고, 비율은 am * 100 / sum으로 구해도 같습니다. 꾸민 글에 이름을 붙이지 않고 ${} 안에서 toFixed(1)을 불러도 됩니다.
  • 찍은 화면이 위와 같고 둘째 시험 값도 맞으면 맞습니다.
  • 흔한 오답 하나는 '2. 수로 바꾸기'를 빠뜨리는 것입니다. +가 두 글을 이어 붙여 하루 매출이 엉뚱한 수가 되고, 나누기는 그 글을 수로 바꿔 아주 작은 비율을 냅니다(문자열과 수를 가리지 않는 생각).
let am = '84000';
let pm = '126500';
const sum = am + pm;
const rate = am / sum * 100;
const text = rate.toFixed(1);
console.log(`하루 ${sum}원`);
console.log(`오전 ${text}%`);
실행 결과
하루 84000126500원
오전 0.0%
  • 다른 흔한 오답은 toFixed(1)을 빠뜨리는 것입니다. 그러면 오전 39.90498812351544%⁠처럼 소수점 아래가 길게 찍힙니다.

다시 볼 레슨: 글자를 수로: Number와 NaN · 템플릿 문자열로 출력 꾸미기

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로