WeniVooks

검색

코딩 테스트 에센셜 with 자바스크립트

문자열 처리

1. 문자열 처리 문제

문자열 처리는 코딩테스트에서 자주 출제되는 유형입니다. JavaScript의 문자열 메서드를 잘 활용하면 빠르게 해결할 수 있습니다.

1.1 문자열 문제의 특징
  • 파싱(Parsing): 문자열에서 필요한 정보 추출
  • 변환(Transformation): 특정 규칙에 따라 문자열 변경
  • 검증(Validation): 패턴 일치, 조건 확인
  • 정규표현식: 복잡한 패턴 매칭에 활용

2. 필수 문자열 메서드

2.1 기본 메서드
const s = "Hello World";
 
// 대소문자 변환
console.log(s.toLowerCase());       // "hello world"
console.log(s.toUpperCase());       // "HELLO WORLD"
 
// 검색
console.log(s.indexOf("o"));        // 4 (첫 번째 위치, 없으면 -1)
console.log(s.lastIndexOf("o"));    // 7 (마지막 위치)
console.log(s.includes("World"));   // true
console.log(s.search(/o/));         // 4 (정규식 검색)
 
// 개수 세기 (직접 구현)
const count = (str, char) => str.split(char).length - 1;
console.log(count(s, "o"));         // 2
 
// 시작/끝 확인
console.log(s.startsWith("Hello")); // true
console.log(s.endsWith("ld"));      // true
 
// 공백 처리
const s2 = "  hello  ";
console.log(s2.trim());             // "hello" (양쪽 공백 제거)
console.log(s2.trimStart());        // "hello  " (왼쪽 공백 제거)
console.log(s2.trimEnd());          // "  hello" (오른쪽 공백 제거)
const s = "Hello World";
 
// 대소문자 변환
console.log(s.toLowerCase());       // "hello world"
console.log(s.toUpperCase());       // "HELLO WORLD"
 
// 검색
console.log(s.indexOf("o"));        // 4 (첫 번째 위치, 없으면 -1)
console.log(s.lastIndexOf("o"));    // 7 (마지막 위치)
console.log(s.includes("World"));   // true
console.log(s.search(/o/));         // 4 (정규식 검색)
 
// 개수 세기 (직접 구현)
const count = (str, char) => str.split(char).length - 1;
console.log(count(s, "o"));         // 2
 
// 시작/끝 확인
console.log(s.startsWith("Hello")); // true
console.log(s.endsWith("ld"));      // true
 
// 공백 처리
const s2 = "  hello  ";
console.log(s2.trim());             // "hello" (양쪽 공백 제거)
console.log(s2.trimStart());        // "hello  " (왼쪽 공백 제거)
console.log(s2.trimEnd());          // "  hello" (오른쪽 공백 제거)
2.2 분리와 결합
// split: 문자열 분리
const s = "apple,banana,cherry";
console.log(s.split(","));          // ["apple", "banana", "cherry"]
 
const s2 = "hello world python";
console.log(s2.split(" "));         // ["hello", "world", "python"] (공백 기준)
console.log(s2.split(" ", 2));      // ["hello", "world"] (최대 2개)
 
// join: 문자열 결합
const words = ["hello", "world"];
console.log(words.join(" "));       // "hello world"
console.log(words.join("-"));       // "hello-world"
console.log(words.join(""));        // "helloworld"
 
// 줄 단위 분리
const text = "line1\nline2\nline3";
console.log(text.split("\n"));      // ["line1", "line2", "line3"]
// split: 문자열 분리
const s = "apple,banana,cherry";
console.log(s.split(","));          // ["apple", "banana", "cherry"]
 
const s2 = "hello world python";
console.log(s2.split(" "));         // ["hello", "world", "python"] (공백 기준)
console.log(s2.split(" ", 2));      // ["hello", "world"] (최대 2개)
 
// join: 문자열 결합
const words = ["hello", "world"];
console.log(words.join(" "));       // "hello world"
console.log(words.join("-"));       // "hello-world"
console.log(words.join(""));        // "helloworld"
 
// 줄 단위 분리
const text = "line1\nline2\nline3";
console.log(text.split("\n"));      // ["line1", "line2", "line3"]
2.3 치환과 추출
// replace: 문자열 치환
const s = "hello world";
console.log(s.replace("world", "javascript"));  // "hello javascript"
console.log(s.replace("l", "L"));               // "heLlo world" (첫 번째만)
console.log(s.replaceAll("l", "L"));            // "heLLo worLd" (모두)
console.log(s.replace(/l/g, "L"));              // "heLLo worLd" (정규식)
 
// 부분 문자열 추출
const str = "Hello World";
console.log(str.slice(0, 5));       // "Hello"
console.log(str.slice(-5));         // "World"
console.log(str.substring(0, 5));   // "Hello"
console.log(str.charAt(0));         // "H"
console.log(str[0]);                // "H"
 
// 패딩
console.log("5".padStart(3, "0"));  // "005"
console.log("5".padEnd(3, "0"));    // "500"
// replace: 문자열 치환
const s = "hello world";
console.log(s.replace("world", "javascript"));  // "hello javascript"
console.log(s.replace("l", "L"));               // "heLlo world" (첫 번째만)
console.log(s.replaceAll("l", "L"));            // "heLLo worLd" (모두)
console.log(s.replace(/l/g, "L"));              // "heLLo worLd" (정규식)
 
// 부분 문자열 추출
const str = "Hello World";
console.log(str.slice(0, 5));       // "Hello"
console.log(str.slice(-5));         // "World"
console.log(str.substring(0, 5));   // "Hello"
console.log(str.charAt(0));         // "H"
console.log(str[0]);                // "H"
 
// 패딩
console.log("5".padStart(3, "0"));  // "005"
console.log("5".padEnd(3, "0"));    // "500"
2.4 문자 종류 확인
// 문자 종류 확인 (정규식 활용)
const isAlpha = (s) => /^[a-zA-Z]+$/.test(s);
const isDigit = (s) => /^\d+$/.test(s);
const isAlphaNum = (s) => /^[a-zA-Z0-9]+$/.test(s);
const isSpace = (s) => /^\s+$/.test(s);
const isUpper = (s) => /^[A-Z]+$/.test(s);
const isLower = (s) => /^[a-z]+$/.test(s);
 
console.log(isAlpha("abc"));        // true
console.log(isDigit("123"));        // true
console.log(isAlphaNum("abc123"));  // true
console.log(isSpace("   "));        // true
console.log(isUpper("ABC"));        // true
console.log(isLower("abc"));        // true
 
// 아스키 코드
console.log("A".charCodeAt(0));     // 65
console.log("a".charCodeAt(0));     // 97
console.log("0".charCodeAt(0));     // 48
console.log(String.fromCharCode(65)); // 'A'
console.log(String.fromCharCode(97)); // 'a'
// 문자 종류 확인 (정규식 활용)
const isAlpha = (s) => /^[a-zA-Z]+$/.test(s);
const isDigit = (s) => /^\d+$/.test(s);
const isAlphaNum = (s) => /^[a-zA-Z0-9]+$/.test(s);
const isSpace = (s) => /^\s+$/.test(s);
const isUpper = (s) => /^[A-Z]+$/.test(s);
const isLower = (s) => /^[a-z]+$/.test(s);
 
console.log(isAlpha("abc"));        // true
console.log(isDigit("123"));        // true
console.log(isAlphaNum("abc123"));  // true
console.log(isSpace("   "));        // true
console.log(isUpper("ABC"));        // true
console.log(isLower("abc"));        // true
 
// 아스키 코드
console.log("A".charCodeAt(0));     // 65
console.log("a".charCodeAt(0));     // 97
console.log("0".charCodeAt(0));     // 48
console.log(String.fromCharCode(65)); // 'A'
console.log(String.fromCharCode(97)); // 'a'

3. 자주 사용하는 문자열 패턴

3.1 회문(팰린드롬) 검사
function isPalindrome(s) {
    // 회문인지 확인 (대소문자 구분 없이, 알파벳/숫자만)
    // 알파벳과 숫자만 추출하고 소문자로 변환
    const cleaned = s.toLowerCase().replace(/[^a-z0-9]/g, '');
    return cleaned === cleaned.split('').reverse().join('');
}
 
 
console.log(isPalindrome("A man, a plan, a canal: Panama"));  // true
console.log(isPalindrome("race a car"));  // false
function isPalindrome(s) {
    // 회문인지 확인 (대소문자 구분 없이, 알파벳/숫자만)
    // 알파벳과 숫자만 추출하고 소문자로 변환
    const cleaned = s.toLowerCase().replace(/[^a-z0-9]/g, '');
    return cleaned === cleaned.split('').reverse().join('');
}
 
 
console.log(isPalindrome("A man, a plan, a canal: Panama"));  // true
console.log(isPalindrome("race a car"));  // false
3.2 애너그램 검사
function isAnagram(s1, s2) {
    // 두 문자열이 애너그램인지 확인
    // 정렬 비교
    const sort = (s) => s.toLowerCase().split('').sort().join('');
    return sort(s1) === sort(s2);
}
 
 
function isAnagramMap(s1, s2) {
    // Map 사용
    if (s1.length !== s2.length) return false;
 
    const count = new Map();
 
    for (const c of s1.toLowerCase()) {
        count.set(c, (count.get(c) || 0) + 1);
    }
 
    for (const c of s2.toLowerCase()) {
        if (!count.has(c)) return false;
        count.set(c, count.get(c) - 1);
        if (count.get(c) === 0) count.delete(c);
    }
 
    return count.size === 0;
}
 
 
console.log(isAnagram("listen", "silent"));  // true
console.log(isAnagram("hello", "world"));    // false
function isAnagram(s1, s2) {
    // 두 문자열이 애너그램인지 확인
    // 정렬 비교
    const sort = (s) => s.toLowerCase().split('').sort().join('');
    return sort(s1) === sort(s2);
}
 
 
function isAnagramMap(s1, s2) {
    // Map 사용
    if (s1.length !== s2.length) return false;
 
    const count = new Map();
 
    for (const c of s1.toLowerCase()) {
        count.set(c, (count.get(c) || 0) + 1);
    }
 
    for (const c of s2.toLowerCase()) {
        if (!count.has(c)) return false;
        count.set(c, count.get(c) - 1);
        if (count.get(c) === 0) count.delete(c);
    }
 
    return count.size === 0;
}
 
 
console.log(isAnagram("listen", "silent"));  // true
console.log(isAnagram("hello", "world"));    // false
3.3 괄호 검증
function isValidParentheses(s) {
    // 괄호 쌍이 올바른지 확인
    const stack = [];
    const pairs = { ')': '(', '}': '{', ']': '[' };
 
    for (const char of s) {
        if ('({['.includes(char)) {
            stack.push(char);
        } else if (')}]'.includes(char)) {
            if (stack.length === 0 || stack[stack.length - 1] !== pairs[char]) {
                return false;
            }
            stack.pop();
        }
    }
 
    return stack.length === 0;
}
 
 
console.log(isValidParentheses("()[]{}"));    // true
console.log(isValidParentheses("(]"));        // false
console.log(isValidParentheses("([)]"));      // false
console.log(isValidParentheses("{[]}"));      // true
function isValidParentheses(s) {
    // 괄호 쌍이 올바른지 확인
    const stack = [];
    const pairs = { ')': '(', '}': '{', ']': '[' };
 
    for (const char of s) {
        if ('({['.includes(char)) {
            stack.push(char);
        } else if (')}]'.includes(char)) {
            if (stack.length === 0 || stack[stack.length - 1] !== pairs[char]) {
                return false;
            }
            stack.pop();
        }
    }
 
    return stack.length === 0;
}
 
 
console.log(isValidParentheses("()[]{}"));    // true
console.log(isValidParentheses("(]"));        // false
console.log(isValidParentheses("([)]"));      // false
console.log(isValidParentheses("{[]}"));      // true
3.4 문자열 압축
function compressString(s) {
    // 연속된 문자 압축 (예: "aabccc" → "a2bc3")
    if (!s) return "";
 
    const result = [];
    let count = 1;
 
    for (let i = 1; i < s.length; i++) {
        if (s[i] === s[i - 1]) {
            count++;
        } else {
            result.push(s[i - 1]);
            if (count > 1) {
                result.push(String(count));
            }
            count = 1;
        }
    }
 
    // 마지막 문자 처리
    result.push(s[s.length - 1]);
    if (count > 1) {
        result.push(String(count));
    }
 
    return result.join('');
}
 
 
console.log(compressString("aabcccccaaa"));  // "a2bc5a3"
console.log(compressString("abc"));          // "abc"
function compressString(s) {
    // 연속된 문자 압축 (예: "aabccc" → "a2bc3")
    if (!s) return "";
 
    const result = [];
    let count = 1;
 
    for (let i = 1; i < s.length; i++) {
        if (s[i] === s[i - 1]) {
            count++;
        } else {
            result.push(s[i - 1]);
            if (count > 1) {
                result.push(String(count));
            }
            count = 1;
        }
    }
 
    // 마지막 문자 처리
    result.push(s[s.length - 1]);
    if (count > 1) {
        result.push(String(count));
    }
 
    return result.join('');
}
 
 
console.log(compressString("aabcccccaaa"));  // "a2bc5a3"
console.log(compressString("abc"));          // "abc"

4. 문자열 실전 문제

4.1 유효한 사용자명 만들기
function makeValidUsername(username) {
    // 사용자명을 규칙에 맞게 변환합니다.
    //
    // 규칙:
    // 1. 소문자로 변환
    // 2. 알파벳, 숫자, 하이픈, 언더스코어, 마침표만 허용
    // 3. 연속된 마침표를 하나로
    // 4. 처음과 끝의 마침표 제거
    // 5. 빈 문자열이면 "a"
    // 6. 15자 초과시 자르고 끝 마침표 제거
    // 7. 2자 이하면 마지막 문자 반복
 
    // 1단계: 소문자로 변환
    let answer = username.toLowerCase();
 
    // 2단계: 허용 문자만 남기기
    answer = answer.replace(/[^a-z0-9\-_.]/g, '');
 
    // 3단계: 연속된 마침표를 하나로
    answer = answer.replace(/\.+/g, '.');
 
    // 4단계: 처음과 끝의 마침표 제거
    answer = answer.replace(/^\.|\.$/g, '');
 
    // 5단계: 빈 문자열이면 "a"
    if (!answer) {
        answer = "a";
    }
 
    // 6단계: 15자 초과시 자르고 끝 마침표 제거
    if (answer.length > 15) {
        answer = answer.slice(0, 15).replace(/\.$/, '');
    }
 
    // 7단계: 2자 이하면 마지막 문자 반복
    while (answer.length < 3) {
        answer += answer[answer.length - 1];
    }
 
    return answer;
}
 
 
console.log(makeValidUsername("...!@BaT#*..y.abcdefghijklm"));
// "bat.y.abcdefghi"
function makeValidUsername(username) {
    // 사용자명을 규칙에 맞게 변환합니다.
    //
    // 규칙:
    // 1. 소문자로 변환
    // 2. 알파벳, 숫자, 하이픈, 언더스코어, 마침표만 허용
    // 3. 연속된 마침표를 하나로
    // 4. 처음과 끝의 마침표 제거
    // 5. 빈 문자열이면 "a"
    // 6. 15자 초과시 자르고 끝 마침표 제거
    // 7. 2자 이하면 마지막 문자 반복
 
    // 1단계: 소문자로 변환
    let answer = username.toLowerCase();
 
    // 2단계: 허용 문자만 남기기
    answer = answer.replace(/[^a-z0-9\-_.]/g, '');
 
    // 3단계: 연속된 마침표를 하나로
    answer = answer.replace(/\.+/g, '.');
 
    // 4단계: 처음과 끝의 마침표 제거
    answer = answer.replace(/^\.|\.$/g, '');
 
    // 5단계: 빈 문자열이면 "a"
    if (!answer) {
        answer = "a";
    }
 
    // 6단계: 15자 초과시 자르고 끝 마침표 제거
    if (answer.length > 15) {
        answer = answer.slice(0, 15).replace(/\.$/, '');
    }
 
    // 7단계: 2자 이하면 마지막 문자 반복
    while (answer.length < 3) {
        answer += answer[answer.length - 1];
    }
 
    return answer;
}
 
 
console.log(makeValidUsername("...!@BaT#*..y.abcdefghijklm"));
// "bat.y.abcdefghi"
4.2 단위별 문자열 압축
function minCompressedLength(s) {
    // 문자열을 여러 단위로 압축해보고 가장 짧은 길이를 반환합니다.
    //
    // 압축 규칙:
    // - 연속으로 반복되는 부분 문자열을 "반복횟수+문자열"로 표현
    // - 예: "aabbaccc" → "2a2ba3c" (1단위), 길이 7
 
    if (s.length === 1) {
        return 1;
    }
 
    let minLength = s.length;
 
    // 1개 ~ len(s)//2개 단위로 압축 시도
    for (let unit = 1; unit <= Math.floor(s.length / 2); unit++) {
        const compressed = [];
        let prev = s.slice(0, unit);
        let count = 1;
 
        for (let i = unit; i < s.length; i += unit) {
            const curr = s.slice(i, i + unit);
 
            if (curr === prev) {
                count++;
            } else {
                if (count > 1) {
                    compressed.push(String(count));
                }
                compressed.push(prev);
                prev = curr;
                count = 1;
            }
        }
 
        // 마지막 처리
        if (count > 1) {
            compressed.push(String(count));
        }
        compressed.push(prev);
 
        const result = compressed.join('');
        minLength = Math.min(minLength, result.length);
    }
 
    return minLength;
}
 
 
console.log(minCompressedLength("aabbaccc"));        // 7 ("2a2ba3c")
console.log(minCompressedLength("ababcdcdababcdcd"));  // 9 ("2ababcdcd")
console.log(minCompressedLength("abcabcdede"));      // 8 ("2abcdede")
function minCompressedLength(s) {
    // 문자열을 여러 단위로 압축해보고 가장 짧은 길이를 반환합니다.
    //
    // 압축 규칙:
    // - 연속으로 반복되는 부분 문자열을 "반복횟수+문자열"로 표현
    // - 예: "aabbaccc" → "2a2ba3c" (1단위), 길이 7
 
    if (s.length === 1) {
        return 1;
    }
 
    let minLength = s.length;
 
    // 1개 ~ len(s)//2개 단위로 압축 시도
    for (let unit = 1; unit <= Math.floor(s.length / 2); unit++) {
        const compressed = [];
        let prev = s.slice(0, unit);
        let count = 1;
 
        for (let i = unit; i < s.length; i += unit) {
            const curr = s.slice(i, i + unit);
 
            if (curr === prev) {
                count++;
            } else {
                if (count > 1) {
                    compressed.push(String(count));
                }
                compressed.push(prev);
                prev = curr;
                count = 1;
            }
        }
 
        // 마지막 처리
        if (count > 1) {
            compressed.push(String(count));
        }
        compressed.push(prev);
 
        const result = compressed.join('');
        minLength = Math.min(minLength, result.length);
    }
 
    return minLength;
}
 
 
console.log(minCompressedLength("aabbaccc"));        // 7 ("2a2ba3c")
console.log(minCompressedLength("ababcdcdababcdcd"));  // 9 ("2ababcdcd")
console.log(minCompressedLength("abcabcdede"));      // 8 ("2abcdede")
4.3 괄호 짝 검증
function isValidParenthesesSimple(s) {
    // '('와 ')'로만 이루어진 문자열이 올바른 괄호 쌍인지 확인합니다.
    //
    // 올바른 괄호:
    // - 모든 '('에 대응하는 ')'가 있음
    // - ')'가 '('보다 먼저 나오면 안 됨
 
    let count = 0;
 
    for (const char of s) {
        if (char === '(') {
            count++;
        } else {
            count--;
            if (count < 0) {  // ')'가 먼저 나온 경우
                return false;
            }
        }
    }
 
    return count === 0;
}
 
 
console.log(isValidParenthesesSimple("()()"));    // true
console.log(isValidParenthesesSimple("(())()"));  // true
console.log(isValidParenthesesSimple(")()("));    // false
function isValidParenthesesSimple(s) {
    // '('와 ')'로만 이루어진 문자열이 올바른 괄호 쌍인지 확인합니다.
    //
    // 올바른 괄호:
    // - 모든 '('에 대응하는 ')'가 있음
    // - ')'가 '('보다 먼저 나오면 안 됨
 
    let count = 0;
 
    for (const char of s) {
        if (char === '(') {
            count++;
        } else {
            count--;
            if (count < 0) {  // ')'가 먼저 나온 경우
                return false;
            }
        }
    }
 
    return count === 0;
}
 
 
console.log(isValidParenthesesSimple("()()"));    // true
console.log(isValidParenthesesSimple("(())()"));  // true
console.log(isValidParenthesesSimple(")()("));    // false
4.4 점수 계산기
function calculateScore(scoreString) {
    // 점수 문자열을 파싱하여 총점을 계산합니다.
    //
    // 형식: 숫자(0~10) + 보너스(S/D/T) + 옵션(*/#)
    // - S: 1제곱, D: 2제곱, T: 3제곱
    // - *: 해당 점수와 이전 점수 2배
    // - #: 해당 점수 마이너스
    //
    // 예: "1S2D*3T" → 1^1*2 + 2^2*2 + 3^3 = 2 + 8 + 27 = 37
 
    // 정규표현식으로 파싱
    const pattern = /(\d+)([SDT])([*#]?)/g;
    const matches = [...scoreString.matchAll(pattern)];
 
    const scores = [];
    const power = { 'S': 1, 'D': 2, 'T': 3 };
 
    for (const [, num, bonus, option] of matches) {
        let score = Math.pow(parseInt(num, 10), power[bonus]);
 
        if (option === '*') {
            score *= 2;
            if (scores.length > 0) {
                scores[scores.length - 1] *= 2;
            }
        } else if (option === '#') {
            score *= -1;
        }
 
        scores.push(score);
    }
 
    return scores.reduce((a, b) => a + b, 0);
}
 
 
console.log(calculateScore("1S2D*3T"));   // 37
console.log(calculateScore("1D2S#10S"));  // 9
console.log(calculateScore("1D2S0T"));    // 3
function calculateScore(scoreString) {
    // 점수 문자열을 파싱하여 총점을 계산합니다.
    //
    // 형식: 숫자(0~10) + 보너스(S/D/T) + 옵션(*/#)
    // - S: 1제곱, D: 2제곱, T: 3제곱
    // - *: 해당 점수와 이전 점수 2배
    // - #: 해당 점수 마이너스
    //
    // 예: "1S2D*3T" → 1^1*2 + 2^2*2 + 3^3 = 2 + 8 + 27 = 37
 
    // 정규표현식으로 파싱
    const pattern = /(\d+)([SDT])([*#]?)/g;
    const matches = [...scoreString.matchAll(pattern)];
 
    const scores = [];
    const power = { 'S': 1, 'D': 2, 'T': 3 };
 
    for (const [, num, bonus, option] of matches) {
        let score = Math.pow(parseInt(num, 10), power[bonus]);
 
        if (option === '*') {
            score *= 2;
            if (scores.length > 0) {
                scores[scores.length - 1] *= 2;
            }
        } else if (option === '#') {
            score *= -1;
        }
 
        scores.push(score);
    }
 
    return scores.reduce((a, b) => a + b, 0);
}
 
 
console.log(calculateScore("1S2D*3T"));   // 37
console.log(calculateScore("1D2S#10S"));  // 9
console.log(calculateScore("1D2S0T"));    // 3

5. 정규표현식 기초

복잡한 문자열 패턴을 처리할 때 유용합니다.

5.1 기본 패턴
const text = "Hello123World456";
 
// 숫자만 추출
console.log(text.match(/\d+/g));  // ['123', '456']
 
// 알파벳만 추출
console.log(text.match(/[a-zA-Z]+/g));  // ['Hello', 'World']
 
// 패턴 치환
console.log(text.replace(/\d+/g, 'X'));  // "HelloXWorldX"
 
// 패턴 분리
console.log(text.split(/\d+/));  // ['Hello', 'World', '']
const text = "Hello123World456";
 
// 숫자만 추출
console.log(text.match(/\d+/g));  // ['123', '456']
 
// 알파벳만 추출
console.log(text.match(/[a-zA-Z]+/g));  // ['Hello', 'World']
 
// 패턴 치환
console.log(text.replace(/\d+/g, 'X'));  // "HelloXWorldX"
 
// 패턴 분리
console.log(text.split(/\d+/));  // ['Hello', 'World', '']
5.2 자주 사용하는 정규표현식
// 이메일 추출
const text1 = "연락처: test@example.com, admin@test.co.kr";
const emails = text1.match(/[\w.-]+@[\w.-]+\.\w+/g);
console.log(emails);  // ['test@example.com', 'admin@test.co.kr']
 
// 전화번호 추출
const text2 = "연락처: 010-1234-5678, 02-123-4567";
const phones = text2.match(/\d{2,3}-\d{3,4}-\d{4}/g);
console.log(phones);  // ['010-1234-5678', '02-123-4567']
 
// HTML 태그 제거
const html = "<p>Hello</p><div>World</div>";
const clean = html.replace(/<[^>]+>/g, '');
console.log(clean);  // "HelloWorld"
 
// 공백 정리 (연속 공백을 하나로)
const text3 = "Hello    World   JavaScript";
const cleaned = text3.replace(/\s+/g, ' ');
console.log(cleaned);  // "Hello World JavaScript"
// 이메일 추출
const text1 = "연락처: test@example.com, admin@test.co.kr";
const emails = text1.match(/[\w.-]+@[\w.-]+\.\w+/g);
console.log(emails);  // ['test@example.com', 'admin@test.co.kr']
 
// 전화번호 추출
const text2 = "연락처: 010-1234-5678, 02-123-4567";
const phones = text2.match(/\d{2,3}-\d{3,4}-\d{4}/g);
console.log(phones);  // ['010-1234-5678', '02-123-4567']
 
// HTML 태그 제거
const html = "<p>Hello</p><div>World</div>";
const clean = html.replace(/<[^>]+>/g, '');
console.log(clean);  // "HelloWorld"
 
// 공백 정리 (연속 공백을 하나로)
const text3 = "Hello    World   JavaScript";
const cleaned = text3.replace(/\s+/g, ' ');
console.log(cleaned);  // "Hello World JavaScript"
5.3 정규표현식 주요 메타문자
패턴설명예시
\d숫자\d+ → "123"
\w알파벳+숫자+_\w+ → "hello_123"
\s공백\s+ → " "
.모든 문자a.c → "abc", "a1c"
*0개 이상ab* → "a", "ab", "abb"
+1개 이상ab+ → "ab", "abb"
?0개 또는 1개ab? → "a", "ab"
[]문자 클래스[aeiou] → 모음
^시작^Hello
$World$

6. 문자열 팁

문자열 문제 체크리스트

  1. 문자열은 불변: 수정할 때 새 문자열 생성됨
  2. 배열로 변환: 자주 수정해야 할 때 s.split('')join('')
  3. 슬라이싱 활용: s.split('').reverse().join('') 뒤집기
  4. Map 활용: 문자 빈도 계산
  5. 정규표현식: 복잡한 패턴은 RegExp 활용

7. 연습문제

4.5 구현과 시뮬레이션4.7 투 포인터와 슬라이딩 윈도우