본문 바로가기

Programmer/JAVASCRIPT

JavaScript 특정 특수문자와 한자만 입력 가능하도록 제한

웹 입력 폼에서 모든 특수문자를 허용하면
데이터 정합성 문제가 발생하는 경우가 있다.

실제로 리포트 생성 도구를 사용하는 과정에서,
특정 특수문자가 입력되면
리포트 생성 단계에서 오류가 발생하는 문제가 있었다.

리포트 툴 내부 로직을 수정하기 어려운 상황이었고,
오류의 정확한 원인을 즉시 파악하기도 쉽지 않았다.

그 결과,
입력 단계에서 차라리 허용 가능한 특수기호만 제한하는 방향으로
문제를 해결하게 되었다.

이 글에서는
키보드 기본 특수기호 일부와 숫자, 영문, 한글, 한자만
입력 가능하도록 제한한 JavaScript 코드를 정리한다.
(붙여 넣기 입력까지 함께 처리한다)


요구사항 정리

입력 제한 조건은 다음과 같았다.

허용

  • 숫자 (0–9)
  • 영문 (a–z, A–Z)
  • 한글 (초성·중성·완성형)
  • 한자 (CJK)
  • 키보드 기본 특수기호 일부

차단

  • 키보드에 없는 특수문자
  • 복사/붙여 넣기로 들어오는 비허용 문자

허용할 특수문자 정의

 
const allowed = '<>-^*()!@#=`~:;%·&?"\\\'_+/,-.';
  • 실제 키보드에서 자주 사용하는 기본 기호만 허용
  • includes()로 빠르게 검사 가능

핵심 아이디어

이 문제는 두 가지를 동시에 처리해야 한다.

  1. 키보드 입력 차단 (keydown)
  2. 붙여넣기 정제 (input)

하나만 처리하면 우회 입력이 가능하다.


전체 코드

function setNoSpecialChar(selector) {

    const allowed = '<>-^*()!@#=`~:;%·ㆍ‧&?"\\\'_+/,-.';
    const escapedAllowed = allowed.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');

    // 숫자, 영어, 한글, 한자 + 허용 특수문자만 허용
    const regex = new RegExp('[^0-9a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣' + '\u3400-\u4DBF' + '\u4E00-\u9FFF' + '\uF900-\uFAFF' + '\\s' + escapedAllowed +']', 'g');

    const userMsg = "특수기호는 키보드에 있는 기본 기호만 사용할 수 있습니다.";

    function sanitizeText(value) {
        return value.replace(regex, "");
    }

    // 키보드 입력 제한
    document.addEventListener("keydown", function (e) {
        if (!e.target.matches(selector)) return;

        const key = e.key;

        // 숫자, 영어, 한글, 한자
        if (/^[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\s]$/.test(key)) return;

        // 허용된 특수문자
        if (allowed.includes(key)) return;

        // 그 외 차단
        if (regex.test(key)) {
            e.preventDefault();
            alert(userMsg);
        }
    });

    // 붙여넣기 처리
    document.addEventListener("input", function (e) {
        if (!e.target.matches(selector)) return;

        const before = e.target.value;
        const after = sanitizeText(before);

        if (before !== after) {
            e.target.value = after;
            alert(userMsg);
        }
    });
}

한자 범위 설명 (중요)

 
\u3400-\u4DBF   // CJK 확장 A
\u4E00-\u9FFF   // CJK 통합 한자
\uF900-\uFAFF   // CJK 호환 한자

이 범위를 포함하면
👉 대부분의 일반적인 한자 입력을 처리할 수 있다.


사용 방법

<input type="text" class="only-allow" />
setNoSpecialChar('.only-allow');

왜 keydown + input을 같이 써야 하나?

방식문제
keydown만 사용 붙여넣기 우회 가능
input만 사용 입력 순간 UX 나쁨
둘 다 사용 ✅ 가장 안정적

중복 검증 로직에 대한 설명

위 코드에서는
keydown 이벤트와 input 이벤트에서 입력값을 각각 검증하고 있다.

작성 당시에는

  • 키보드 입력 단계에서 즉시 차단하는 역할과
  • 붙여넣기나 우회 입력을 다시 한번 정제하는 역할을

명확히 분리하는 것이 목적이었기 때문에
유사한 검증 로직이 두 군데에 존재하게 되었다.

 

블로그 글을 정리하면서 다시 살펴보니,
허용 문자 정의나 검증 로직을
하나의 공통 함수로 정리할 수 있는 여지도 보인다.

 

다만 실제 동작에는 문제가 없고
현재 서비스에서 안정적으로 사용 중인 코드이기 때문에,
당장 구조를 변경하기보다는
추후 리팩토링 대상으로 남겨두었다.


주의할 점

  • alert() 대신
    실제 서비스에서는 toast / 안내 문구로 교체 권장
  • 모바일 키보드는 e.key 값이 다를 수 있으므로
    PC 환경 기준으로 사용하는 것이 안전
  • 입력 제한은 클라이언트 검증일 뿐,
    서버 단 검증은 반드시 별도로 필요하다.

정리

  • 모든 특수문자를 허용하면
    후처리 단계에서 예기치 않은 오류가 발생할 수 있다.
  • keydown + input을 함께 사용하면
    UX와 데이터 안정성을 모두 확보할 수 있다.
  • 현재 구조는 실무에서 충분히 안정적이며,
    필요시 리팩토링이 가능한 형태로 유지하고 있다.