상세 컨텐츠

본문 제목

[JS] 프론트엔드의 한글 정규식, 어떻게 쓸 것인가.

프론트엔드

by Helia-17 2024. 2. 4. 23:50

본문

 

프론트엔드 개발자라면 가끔 한글과 관련한 이슈를 마주하곤 한다. 그 중에서도 한글 정규식을 적용할 때 겪었던 이슈와 원인, 해결 방식을 정리해보고자 한다. 

 

 

한글 정규식

 

1. /[ㄱ-힣]/을 사용하지 말자.

 

 

한글 정규식을 검색하면 흔히 아래의 정규식이 많이 나온다.

/[ㄱ-힣]/

 

 

 

하지만 권장하지 않는다. 왜냐하면 아래의 일이 일어나기 때문이다.

ㄱ : %u3131 // 우선 당신은 한글 자음부터 모음까지를 허용했다.
...

㆝ : %u319D // 당신은 한자도 허용하기 시작했다.
㈑ : %u3211 // 당신은 괄호 안에 한글이 들어간 특수문자를 허용했다.
㈭ : %u322D // 괄호 안에 한자가 들어간.. 특수문자도 허용했다.
㉡ : %u3261 // 또한 원 안에 한글이 들어간 특수문자도 허용했다.
㌕ : %u3315 // ... 일본어 단위도 허용했다.
㎲ : %u33B2 // 여러가지 국제표준단위를 허용했다.
东 : %u4E1C // ... 중국어 간체자를 허용하기 시작했다.
復 : %u5FA9 // ... 한자는 계속된다...

...

...

...

// 그만 알아보자..

...

...

...

힣 : %uD7A3 // 많은 문자를 허용하고 말았다..

 

 

당신이 허용하게 되는 문자들의 "극히" 일부분을 가져와봤다. 

 

 

즉, "ㄱ"과 "힣"의 유니코드 사이, 즉 "ㄱㄴㄷ..ㅜㅠㅡㅣ"의 구간과 "가나다…힡힢힣"의 구간 사이에 온갖 특수문자 및 언어가 들어간다. 더 자세히 경악하고 싶다면 유니코드가 정리된 페이지에서 ㄱ(%u3131)를 찾은 뒤 힣(%uD7A3)을 만날 때까지 계속 스크롤을 내리고 다음 페이지를 넘어가길 반복하면 된다. (...)

 

 

 

2. 어떤 한글 정규식이 좋을까

 

참고로 유니코드에서 한글이 존재하는 구간은 다음과 같다.

Hangul Jamo (U+1100 to U+11FF)

Hangul Compatibility Jamo (U+3130 to U+318F)

Hangul Jamo Extended-A (U+A960 to U+A97F)

Hangul Syllables (U+AC00 to U+D7AF)

Hangul Jamo Extended-B (U+D7B0 to U+D7FF)

 

이중 /가-힣/으로 걸러낼 수 있는 건 한글 소리 마디 (Hangul Syllables)인데, 한글 자모 각각을 구별하기 위해선 Hangul Jamo까지 살펴보는게 좋다.

다시 말해서,   "ㄱ-힣"보다는"가-힣" 또는  “ㄱ-ㅣ가-힣”을 쓰는 것이 좋다.

완전한 글자만 허용하려면 "가-힣", 자모음도 허용한다면" ㄱ-ㅣ가-힣"을 쓰는게 좋다. (하지만...)

 

 

3. 맥과 윈도우의 인코딩 방식

 

 

여기서 끝이 아니다. 맥과 윈도우가 지원하는 파일명 인코딩 방식이 다르다. 따라서 윈도우에서 문제없는 정규식도 맥에서는 제대로 작동하지 못할 수 있다.

 

 

 

맥의 경우 초성자음과 종성 및 단일 자음의 유니코드 값이 달라진다는 것이다. 그래서 똑같은 가나다도 윈도우에서 작성한 것과, 맥에서 작성한 것을 테스트 해봤을 때 정규식을 통과하지 못하는 경우가 생긴다.

 

 

 

이때, "ㄱ-ㅣ가-힣"만 쓴다면 테스트가 똑같이 보이는 가나다 중 하나만 깨지는 것을 볼 수 있다.

윈도우에서 작성한 가나다는 되지만 맥에서 작성한 가나다는 안돼요 돌아가세요.

 

 

 

맥에서 입력한 ‘가'는 'ㄱㅏ'로 분리되는데  이때의 'ㄱ'와 단독 입력한 'ㄱ'은 같은 자음으로 보이지만 컴퓨터의 입장에서는 유니코드로 'U+1100'과 'U+3131'의 비교라서 다른 것으로 처리 된다. 심지어 종성 ᆨ(U+11A8)도 있다.

초성 기역 / 단독 입력 기역 / 종성 기역

 

 

 

4. 이 모든 것을 고려한 두 가지 해결 방식

 

 

그럼 어떻게 해야 할까, 이를 해결하는 방법으로는 두 가지가 있다.

 

1. 정규식에 이 모든 경우를 포함해주는 방법

2. 정규식 검사를 하기 전에 정규식에 들어갈 텍스트를 NFC로 정규화하는 방법

 

 

1. 정규식에 이 모든 경우를 포함해주는 방법

이 경우 정규식은 아래와 같다. (그대로 복사해 사용이 가능하다.)

/^[ᄀ-ᄒᆨ-ᇂㄱ-ㅣ가-힣ᅡ-ᅵa-zA-Z0-9 !@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]*$/gi

 

 

 

2. 정규식 검사를 하기 전에 정규식에 들어갈 텍스트를 NFC로 정규화하는 방법

 

맥에서 한글을 정규표현식으로 잘 처리하기 위해 맥의 유니코드 문자열을 NFC 정규화 시킨 뒤에 패턴 매칭하는 방법이다.

표준 정규화 방식에는 네 가지가 있다.

 

  • NFC: Normalization Form Canonical Composition
  • NFD: Normalization Form Canonical Decomposition
  • NFKC: Normalization Form Compatibility Composition
  • NFKD: Normalization Form Compatibility Decomposition

 

맥에서는 NDF 방식(문자열을 자음과 모음으로 모두 분해하여 유니코드화 한 뒤 이어붙이는 방식)을 사용하고 있다. 이를 NFC 방식으로 바꾸어주는 방법이다.

 

 

자바스크립트는 문자열 내장 함수로 정규화를 지원하고 있다.

// String.prototype.normalize([form])

const strFromWindow = "가나다"
const strFromMac = "가나다"
console.log(strFromWindow === strFromMac) // false
const normalized = strFromMac.normalize('NFC')
console.log(strFromWindow === normalized) // true

 

따라서 인풋을 통해 입력값을 받을 때 정규식 패턴 매칭 이전에 정규화를 하면 "ㄱ-ㅣ가-힣"의 정규식으로도 원하는 결과를 얻는 것이 가능하다.

 

 

맺음말

한글 정규식을 정하는데 있어서, 가장 중요한 것은 비즈니스 요구사항이다. 완전한 글자만 허용하는지, 자모음도 허용하는지, 드물지만 옛한글까지 지원해야 하는지, 한글에서 실제로 사용하지 않는 자모음 조합도 허용하는지 등이 명확해야 그에 따른 정규식을 만들 수 있다.

비즈니스 요구사항을 명확히 알고, 그에 맞는 한글 정규식을 정해보자!

 

 

참고한 글

[정규식으로 (한글) 문자만 골라내기] https://haah.kr/2017/08/23/alphabetic-letter-validation/

[When "Zoë" !== "Zoë". Or why you need to normalize Unicode strings] https://withblue.ink/2019/03/11/why-you-need-to-normalize-unicode-strings.html

[같은 모양, 다른 값의 한글 자음]https://winplz.tistory.com/entry/한글-자음-비교같지만-다른-자음들

When "Zoë" !== "Zoë". Or why you need to normalize Unicode strings

When "Zoë" !== "Zoë". Or why you need to normalize Unicode strings

관련글 더보기

댓글 영역