읽기 전에 알아두면 좋아요
아래 개념이 익숙하면 본문을 바로 읽으세요. 낯선 개념만 링크에서 복습하면 됩니다.
- JavaScript 배열: 인덱스 조회와 삽입·삭제 비용배열은 여러 값을 순서대로 담습니다. 인덱스로 값을 읽고 반복문으로 하나씩 살펴봅니다.
개념과 예제는 실행하지 않아도 읽을 수 있습니다. 내 컴퓨터·터미널에서 직접 실행하는 과정은 선택 실습입니다.
과정 위치와 선택 복습 안내
과정 위치: 문자열 기초 · 알고리즘 개념
과정 위치는 이 글이 속한 묶음입니다. 이 단계의 모든 개념을 먼저 읽을 필요는 없습니다. 위에 연결한 개념 중 낯선 내용만 복습하세요. 문제의 조건·상태·갱신 순서는 익숙한 언어로 설명하면 됩니다.
JavaScript로 문법·실행 복습하기 (선택)
개념 글의 코드는 JavaScript 예시입니다. 문제 화면에서는 JavaScript·Python·Java·C++·C# 중 익숙한 언어의 함수를 작성하세요. 본문의 Node.js 입출력 예시는 로컬 실행을 위한 별도 안내입니다.
문자열을 순회하며 문자 판별·대소문자 변환·숫자 추출은 어떻게 하나요?
문자열 문제는 한 문자씩 읽고, 조건에 맞는 문자만 세거나 바꾸거나 모으면 됩니다. 읽는 순서를 유지하면 결과의 문자 순서도 유지됩니다.

a0B1c2에서 숫자만 모으면 "012", 이를 수로 바꾸면 12입니다. 문자열의 선행 0과 수의 값은 서로 다릅니다.
적용 조건·범위: JavaScript의 문자열 인덱스와 length는 UTF-16 코드 단위 기준입니다. for...of는 코드 포인트 단위로 진행하지만, 결합 문자나 여러 코드 포인트로 이루어진 이모지가 화면의 한 글자와 항상 일치하지는 않습니다. 이 글의 영문자·가운데 위치 예제는 ASCII 범위로 한정합니다. Unicode 대소문자 변환은 길이가 바뀔 수도 있습니다.
본문 근거: ECMAScript 2025 — String · Unicode UAX #29 · ECMA-402 Segmenter

이 글에서 할 일: 숫자 추출과 대소문자 변환의 판별 조건을 직접 작성합니다. 선수 지식: 변수·조건문·반복문.
숫자를 순서대로 모으기
아래 함수는 ASCII 숫자 0부터 9까지만 고릅니다. 추출한 수가 JavaScript의 안전한 정수 범위 안에 있다는 조건에서 실행합니다. 숫자가 하나도 없으면 수를 null로 돌려줍니다.

아래 JavaScript 예제는 문자열에서 숫자만 골라 원래 순서대로 모은 뒤, 문자열 그대로의 값과 숫자로 변환한 값을 보여줍니다. 코드 아래의 결과와 표를 보면서 두 표현이 어떻게 다른지 살펴보세요. 직접 실행하지 않아도 설명을 따라갈 수 있습니다.
function extractDigits(text) {
const digits = [];
for (const ch of text) {
if (ch >= '0' && ch <= '9') digits.push(ch);
}
const raw = digits.join('');
return { raw, number: raw === '' ? null : Number(raw) };
}
console.log(JSON.stringify(extractDigits('a0B1c2')));
console.log(JSON.stringify(extractDigits('ABC')));
실행 결과
{"raw":"012","number":12}
{"raw":"","number":null}
| 읽은 문자 | 숫자 여부 | 누적 결과 |
|---|---|---|
| a | 아니요 | 빈 문자열 |
| 0 | 예 | 0 |
| B | 아니요 | 0 |
| 1 | 예 | 01 |
| c | 아니요 | 01 |
| 2 | 예 | 012 |
불변식은 “지금까지 읽은 구간의 숫자가 원래 순서대로 모여 있다”입니다. 숫자가 아닌 문자는 건너뛰고, 숫자는 결과 뒤에 붙입니다. 매번 숫자로 누적한다면 value = value × 10 + digit를 사용하지만 선행 0은 보존되지 않습니다.
내 컴퓨터에서 직접 실행하기 — 숫자 추출 예제 (선택)
코드를 직접 바꿔보고 싶은 분을 위한 안내입니다. 이 과정은 방문자 자신의 컴퓨터에서 진행하며, 글을 읽기 위해 반드시 실행할 필요는 없습니다.
준비물: Node.js와 코드 편집기인 Visual Studio Code(VS Code). Node.js는 JavaScript 파일을 컴퓨터에서 실행하는 프로그램입니다. 아직 설치하지 않았다면 두 프로그램의 공식 사이트에서 설치한 뒤 진행하세요.
- 컴퓨터에 연습용 폴더를 하나 만들고, VS Code에서 파일 → 폴더 열기로 그 폴더를 엽니다.
- 그 폴더 안에
extract-digits.js파일을 만듭니다. 위의 JavaScript 예제 전체를 복사해 붙여넣고 저장하세요. 마지막console.log줄도 포함하며, 파일 이름 끝이.js.txt가 되지 않도록 확인합니다. - VS Code의 터미널 → 새 터미널을 선택합니다. 아래쪽에 열린 터미널은 명령어를 입력하는 창입니다. 다음 명령으로 Node.js 설치 여부를 확인합니다.
node --version
v로 시작하는 버전 번호가 나오면 실행할 수 있습니다. 명령을 찾을 수 없다는 메시지가 나오면 Node.js를 설치하고 VS Code를 완전히 닫았다가 다시 여세요.
터미널의 현재 위치가 방금 파일을 저장한 폴더인지 확인한 뒤, 다음 명령을 입력하고 Enter를 누릅니다. 이 명령은 JavaScript 파일 안이 아니라 터미널에 입력합니다.
node extract-digits.js
터미널에 나온 값을 위의 실행 결과와 비교하세요. Cannot find module이 나오면 파일 이름과 저장 여부, 터미널에서 연 폴더가 같은지 확인합니다.
문자 판별과 변환을 분리하기
아래 JavaScript 예제는 영문 대문자와 소문자를 서로 바꾸고 숫자·기호는 그대로 둡니다. 코드 아래의 결과를 보면서 각 문자가 어떤 조건에 해당하는지 살펴보세요. 직접 실행하지 않아도 설명을 따라갈 수 있습니다.

function toggleAscii(text) {
const result = [];
for (const ch of text) {
if (ch >= 'A' && ch <= 'Z') result.push(ch.toLowerCase());
else if (ch >= 'a' && ch <= 'z') result.push(ch.toUpperCase());
else result.push(ch);
}
return result.join('');
}
console.log(toggleAscii('Ab3!'));
실행 결과
aB3!
대문자이면 소문자로, 소문자이면 대문자로 바꿉니다. 숫자와 기호는 그대로 둡니다. ch === ch.toUpperCase()만으로 대문자를 세면 숫자와 기호도 통과할 수 있으므로 먼저 영문자 범위를 판별해야 합니다.
| 목표 | 읽을 때 할 일 |
|---|---|
| 특정 문자 개수 | 목표 문자와 같을 때 count를 1 증가 |
| A를 #으로 바꾸기 | A이면 #을, 나머지는 원래 문자를 결과 뒤에 추가 |
| 대문자로 통일 | ASCII 영문자를 같은 대문자 기준으로 변환 |
| 첫 번째 최장 문자열 | 현재 길이가 저장된 최대 길이보다 클 때만 교체 |
내 컴퓨터에서 직접 실행하기 — 대소문자 변환 예제 (선택)
코드를 직접 바꿔보고 싶은 분을 위한 안내입니다. 이 과정은 방문자 자신의 컴퓨터에서 진행하며, 글을 읽기 위해 반드시 실행할 필요는 없습니다.
준비물: Node.js와 코드 편집기인 Visual Studio Code(VS Code). Node.js는 JavaScript 파일을 컴퓨터에서 실행하는 프로그램입니다. 아직 설치하지 않았다면 두 프로그램의 공식 사이트에서 설치한 뒤 진행하세요.
- 컴퓨터에 연습용 폴더를 하나 만들고, VS Code에서 파일 → 폴더 열기로 그 폴더를 엽니다.
- 그 폴더 안에
toggle-case.js파일을 만듭니다. 위의 JavaScript 예제 전체를 복사해 붙여넣고 저장하세요. 마지막console.log줄도 포함하며, 파일 이름 끝이.js.txt가 되지 않도록 확인합니다. - VS Code의 터미널 → 새 터미널을 선택합니다. 아래쪽에 열린 터미널은 명령어를 입력하는 창입니다. 다음 명령으로 Node.js 설치 여부를 확인합니다.
node --version
v로 시작하는 버전 번호가 나오면 실행할 수 있습니다. 명령을 찾을 수 없다는 메시지가 나오면 Node.js를 설치하고 VS Code를 완전히 닫았다가 다시 여세요.
터미널의 현재 위치가 방금 파일을 저장한 폴더인지 확인한 뒤, 다음 명령을 입력하고 Enter를 누릅니다. 이 명령은 JavaScript 파일 안이 아니라 터미널에 입력합니다.
node toggle-case.js
터미널에 나온 값을 위의 실행 결과와 비교하세요. Cannot find module이 나오면 파일 이름과 저장 여부, 터미널에서 연 폴더가 같은지 확인합니다.
길이와 경계 조건 확인하기
ASCII 문자열 길이가 N이면 가운데 인덱스는 홀수일 때 floor(N / 2) 하나입니다. 짝수일 때는 N / 2 - 1과 N / 2 두 개입니다. 빈 문자열에는 가운데 문자가 없으므로 출력 규칙을 따로 정해야 합니다.

JavaScript의 문자열 인덱스와 length는 UTF-16 코드 단위 기준입니다. for...of는 코드 포인트 단위로 진행하지만, 결합 문자나 여러 코드 포인트로 이루어진 이모지가 화면의 한 글자와 항상 일치하지는 않습니다. 이 글의 영문자·가운데 위치 예제는 ASCII 범위로 한정합니다. Unicode 대소문자 변환은 길이가 바뀔 수도 있습니다.
길이 N을 한 번 읽고 결과를 한 번 결합하므로 위 ASCII 처리의 시간은 O(N), 결과 저장 공간은 O(N)입니다. 숫자 개수만 센다면 결과 문자열이 없어 O(1) 추가 공간으로 충분합니다. 안전한 정수 범위를 넘는 숫자열은 문자열로 보관하거나 해당 언어의 큰 정수형을 선택하세요.
직접 확인하고 문제에 적용하기
z00a7을 넣으면 raw와 number는 각각 무엇일까요? 7!에서 대문자 개수를 세면 몇 개여야 할까요?

답과 이유 확인
raw="007", number=7, 대문자 개수는 0입니다. 숫자와 기호를 영문 대문자로 세지 않는지 확인하세요.
참고 자료
자료 확인일: 2026년 10월 19일.
- ECMAScript 2025 — String — 문자열 순회와 대소문자 변환의 언어 규칙.
재귀 문자열 길이: 무엇을 한 글자로 셀지 먼저 정합니다
첨부 dev/length_of_str.mjs는 문자열의 마지막 부분을 하나 줄이고, 작은 문자열의 길이에 1을 더합니다. 원본 예제 "abcde"의 결과는 5입니다. 이 파일은 길이를 구하는 가장 효율적인 방법보다 기저 조건까지 내려갔다가 답을 돌려주는 재귀 흐름을 보여 줍니다.

내려갈 때 줄이고 돌아올 때 1을 더합니다
| 현재 입력 | 기다리는 계산 | 반환 |
|---|---|---|
"abc" |
strLength("ab") + 1 |
2 + 1 = 3 |
"ab" |
strLength("a") + 1 |
1 + 1 = 2 |
"a" |
strLength("") + 1 |
0 + 1 = 1 |
"" |
기저 조건 | 0 |
표를 위에서 아래로 호출하고 아래에서 위로 반환합니다. 원본의 arr라는 매개변수에는 배열이 아니라 문자열을 넣었습니다. 빈 문자열의 arr[0]은 undefined이므로 arr[0] == null을 통과해 0을 반환합니다. 이 조건은 일반 배열의 길이 검사로 쓰기에는 부적절합니다. 예를 들어 [null, 'a']는 길이가 2여도 첫 원소 때문에 바로 0을 반환합니다. 아래 독립 예제는 문자열만 받고 기저 조건을 part === ''로 명확하게 씁니다.
원본이 세는 단위는 UTF-16 코드 단위입니다
slice(0, -1)은 맨 끝 UTF-16 코드 단위 하나를 제외합니다. 따라서 원본은 화면에서 보이는 글자 수가 아니라 JavaScript의 length와 같은 단위를 셉니다. 예를 들어 "😊"는 코드 단위 2개입니다. 첫 slice 뒤에는 서로 짝을 이루던 두 단위 중 앞쪽 \uD83D만 남고, 다음 slice에서 빈 문자열이 됩니다. 복귀하며 1씩 두 번 더하므로 결과는 2입니다.
| 문자열 | UTF-16 코드 단위 | 코드 포인트 | 문자소 묶음 |
|---|---|---|---|
abcde |
5 | 5 | 5 |
😊 |
2 | 1 | 1 |
e + U+0301 결합 악센트 |
2 | 2 | 1 |
👨👩👧👦 가족 이모지 |
11 | 7 | 1 |
코드 포인트는 for...of로 셉니다. 그러나 e와 결합 악센트처럼 여러 코드 포인트가 한 문자소 묶음이 될 수 있습니다. 글자 수에 가까운 기준이 필요한 기능에서는 Intl.Segmenter의 granularity: 'grapheme'처럼 문자소 경계를 사용합니다. 문자소 묶음도 글꼴의 실제 픽셀 너비나 모든 상황의 사람 인식과 같은 개념은 아닙니다. ASCII 가운데 문자 문제의 단위를 Unicode 전체로 조용히 바꾸지 말고 문제에서 요구하는 기준을 고르세요.
호출 수와 부분 문자열 비용을 따로 셉니다
길이가 n이면 빈 문자열을 포함해 n+1번 호출하고, 복귀마다 1을 더합니다. 따라서 호출과 덧셈의 수는 O(n), 대기하는 호출 스택은 O(n)입니다. 여기에 매번 만든 부분 문자열의 비용을 더해야 합니다. 부분 문자열을 길이만큼 복사하는 비용 모델에서는 복사량이 (n - 1) + (n - 2) + ... + 1이므로 O(n²)입니다. 실제 복사·문자열 공유·저장 방식은 엔진 최적화의 영향을 받으며 ECMAScript가 물리적인 복사 시간과 공간을 보장하지는 않습니다.
아래의 recursiveCodeUnitLength(text)는 원본과 같은 코드 단위 개수를 숫자로 반환하되, 문자열 입력과 학습용 상한 256을 검사합니다. 이 상한은 모든 환경의 재귀 안전 한도가 256이라는 뜻은 아닙니다. 길이가 줄어 종료하는 식이어도 호출 스택이 부족할 수 있으므로 긴 입력의 길이는 text.length를 읽고, 코드 포인트 개수는 반복문으로 세는 편이 적절합니다. 배열 합에서 복사를 없애는 방식은 배열 합의 호출과 복귀 설명과 연결됩니다.
measureText(text)는 같은 입력을 세 기준으로 비교하기 위해 { codeUnits, codePoints, graphemes } 객체를 반환하는 별도 보조 함수입니다. 원본 strLength의 숫자 반환과 구분하세요. 빈 문자열에서는 세 값이 모두 0입니다. 실행 예제는 Intl.Segmenter를 지원하는 JavaScript 환경을 사용하며 파일·네트워크 접근은 하지 않습니다.
문자열 잘라내기와 코드 포인트 순회는 ECMAScript String 규칙, 문자소 경계는 Unicode UAX #29와 ECMA-402 Segmenter를 대조했습니다. 호출 스택 제한은 MDN의 재귀 오류 설명을 참고했습니다.
추가 예제 코드와 실행 방법 펼치기
직접 실행할 때만 펼쳐 보세요. Node.js 시작 안내를 확인하고 supplement-string-length-units.js로 저장합니다.
function recursiveCodeUnitLength(text) {
if (typeof text !== 'string') throw new TypeError('문자열을 넣어 주세요.');
if (text.length > 256) throw new RangeError('재귀 학습 예제는 UTF-16 코드 단위 256개까지만 받습니다.');
function count(part) {
if (part === '') return 0;
return count(part.slice(0, -1)) + 1;
}
return count(text);
}
function measureText(text) {
const codeUnits = recursiveCodeUnitLength(text);
let codePoints = 0;
for (const point of text) codePoints++;
const segmenter = new Intl.Segmenter('ko', { granularity: 'grapheme' });
let graphemes = 0;
for (const segment of segmenter.segment(text)) graphemes++;
return { codeUnits, codePoints, graphemes };
}
console.log('ascii', JSON.stringify(measureText('abcde')));
console.log('emoji', JSON.stringify(measureText('😊')));
console.log('combining', JSON.stringify(measureText('e\u0301')));
console.log('family', JSON.stringify(measureText('👨👩👧👦')));
파일이 있는 폴더의 터미널에서 실행합니다.
node supplement-string-length-units.js
기대 출력
ascii {"codeUnits":5,"codePoints":5,"graphemes":5}
emoji {"codeUnits":2,"codePoints":1,"graphemes":1}
combining {"codeUnits":2,"codePoints":2,"graphemes":1}
family {"codeUnits":11,"codePoints":7,"graphemes":1}
이 글이 도움이 되었나요?
이어서 공부하기
체크포인트: 예제의 상태 변화를 손으로 추적하고 아래 문제에 적용하세요. 값이 없는 경우와 원소 하나인 경우도 설명해 보세요. 같은 문자·찾는 문자 없음·홀짝 길이를 확인하고 결과의 등장 순서를 설명하세요.
이 개념으로 더 풀어보기
다음 추천 · 이 개념으로 풀 문제: A를 #으로 풀이: 문자열 순회와 치환
권장 순서는 학습 가이드와 같습니다. 다른 순서는 접힌 참고 목록에서 확인할 수 있습니다. 읽음 표시는 숙달이나 채점 결과가 아닙니다.
원래 과정 목록 순서 (선택)
읽음 기록
읽음 — / 전체 30개 · 필수 0개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.