-
JS로 한글 종성 유무 판단하기Studying/JavaScript 2021. 11. 22. 21:07
프로젝트를 진행하면서 다음과 같은 고민을 하게 되었다.
위와 같은 화면에서 게임 결과에 따라 마피아의 이름을 동적으로 바꾸어 주어야 하는데,
고양이 이름의 배열과 출력해야 하는 결과는 다음과 같다.
const catNames = ['고등어', '샴', '치즈', '삼색이', '네로', '오드아이']; const mafiaName = catNames[0]; console.log(`마피아는 ${mafiaName}였습니다.`};
이때 고양이의 이름이 '샴'과 같이 받침이 있는 경우에는 '마피아는 샴였습니다.'와 같이 출력되므로
'마피아는 샴이었습니다'와 같이 출력하기 위해서는 조사를 변경해 주어야 한다.
처음에는 다음과 같이 고양이 이름에 조사를 붙여 해결할 수 있지 않을까 생각해 보았다.
const catNames = ['고등어였', '샴이었', '치즈였', '삼색이였', '네로였', '오드아이였']; const mafiaName = catNames[0]; console.log(`마피아는 ${mafiaName}습니다.`};
하지만 이 경우 catNames 배열을 재사용할 수 없다는 문제가 생긴다.
가령 '치즈는 마피아가 아니었습니다.'와 같이 출력하고 싶다면
const catNames2 = ['고등어는', '샴은', '치즈는', '삼색이는', '네로는', '오드아이는']; const civilCatName = catNames[2]; console.log(`${mafiaName} 마피아가 아니었습니다.`};
위와 같이 조사가 바뀔 때마다 새로운 배열을 생성해야 하므로 올바른 해결 방법이 아니다.
문제를 근본적으로 해결하기 위해서는 한글 글자의 받침 유무를 인식하여 조사를 결정해 주어야 한다.
어떻게 이 문제를 해결할 수 있을까?
답은 한글의 UTF-16 코드에서 찾을 수 있다.
한글 '가'와 '나'의 UTF-16 코드를 각각 콘솔로 출력하여 확인해 보자.
const str = '가'; console.log(str.charCodeAt(0)); // 44032
그렇다면 UTF-16 코드가 44033인 한글 글자는 무엇일까?
'가' 다음 글자는 '나'가 아닐까 하고 생각하기 쉽지만UTF-16 코드는 글자를 사전 순으로 나열한 것이므로 '각'이 다음 글자가 된다.
console.log(String.fromCharCode(44033)); // '각'
사전 순으로 어떤 글자가 순서대로 나올지 예상하기 어려우므로 44032부터 44081까지 순서대로 50개의 한글 글자를 콘솔로 출력하여 확인해 보았다.
let str = ''; for(let i = 44032; i < 44082; i++){ str += ` ${String.fromCharCode(i)}`; } console.log(str); // " 가 각 갂 갃 간 갅 갆 갇 갈 갉 갊 갋 갌 갍 갎 갏 감 갑 값 갓 갔 강 갖 갗 갘 같 갚 갛 개 객 갞 갟 갠 갡 갢 갣 갤 갥 갦 갧 갨 갩 갪 갫 갬 갭 갮 갯 갰 갱"
순서대로 출력된 글자를 관찰해 보면 "가 각 갂 갃 간 갅 갆 갇 갈 갉 갊 갋 갌 갍 갎 갏 감 갑 값 갓 갔 강 갖 갗 갘 같 갚 갛"까지
초성이 'ㄱ', 중성이 'ㅏ'이고 종성만 달라지고 있는 것을 확인할 수 있다.
이 후로 다시 초성이 'ㄱ', 중성이 'ㅐ'인 "개 객 갞 갟 갠 갡 갢 갣 갤 갥 갦 갧 갨 갩 갪 갫 갬..."이 나타난다.
UTF-16 코드를 순서대로 더 많이 출력해 보며 글자를 관찰해 보면
초성과 중성이 같고 받침만 다른 글자들이 28개씩 반복된다는 것을 알 수 있다.
즉 '가', '개'...와 같이 받침이 없는 한글 글자들이 28개마다 반복되는 규칙을 가지고 있다.
그렇다면 임의의 한글 글자가 받침을 가지고 있는 글자인지 어떻게 알아낼 수 있을까?
확인하려는 글자의 UTF-16 코드를 28로 나눈 나머지가 '가'의 UTF-16 코드(44032)를 28로 나눈 나머지(6)와 같은지를 확인해 보면 된다. 이를 이용해 임의의 한글 글자를 입력받으면 받침을 가지고 있는 글자인지 알려주는 함수를 작성해 보자.
const hasFinalConsonant = korChar => { const CHAR_CODE_OF_KOR_GA = 44032; return korChar.charCodeAt(0) % 28 !== CHAR_CODE_OF_KOR_GA % 28; }; console.log(hasFinalConsonant('비')); // false console.log(hasFinalConsonant('빕')); // true
이를 응용하면 특정 받침을 가진 글자인지 판단할 수 있는 함수도 작성할 수 있다.
예를 들어 'ㄹㄱ' 받침으로 끝나는 글자도 28개마다 반복되므로 임의의 글자의 UTF-16 코드를 28로 나눈 나머지가 '갉'의 UTF-16 코드를 28로 나눈 나머지와 같은지를 확인하면 되는 것이다.
다시 처음의 문제로 돌아가 보자.
임의의 한글 고양이 이름의 마지막 글자가 받침을 가진 글자인지 확인한 후
받침이 있는 글자로 끝나는 고양이 이름과 받침이 없는 글자로 끝나는 고양이 이름에 각각 다른 조사를 적용해 주면 된다.
이를 위해 먼저 한글 단어의 마지막 글자를 반환해 주는 함수를 만들자.
const getLastChar = korStr => korStr[korStr.length - 1]; console.log(getLastChar('고등어')); // '어'
이제 지금까지 만든 함수들을 조합하면 문제를 해결할 수 있다.
const catNames = ['고등어', '샴', '치즈', '삼색이', '네로', '오드아이']; const mafiaName = catNames[0]; const getLastChar = korStr => korStr[korStr.length - 1]; const hasFinalConsonant = korChar => { const CHAR_CODE_OF_KOR_GA = 44032; return korChar.charCodeAt(0) % 28 !== CHAR_CODE_OF_KOR_GA % 28; }; console.log( `마피아는 ${mafiaName}${hasFinalConsonant(getLastChar(mafiaName)) ? '이었' : '였'}습니다.` ); // '마피아는 고등어였습니다.'
const catNames = ['고등어', '샴', '치즈', '삼색이', '네로', '오드아이']; const mafiaName = catNames[1]; const getLastChar = korStr => korStr[korStr.length - 1]; const hasFinalConsonant = korChar => { const CHAR_CODE_OF_KOR_GA = 44032; return korChar.charCodeAt(0) % 28 !== CHAR_CODE_OF_KOR_GA % 28; }; console.log( `마피아는 ${mafiaName}${hasFinalConsonant(getLastChar(mafiaName)) ? '이었' : '였'}습니다.` ); // '마피아는 샴이었습니다.'
반응형'Studying > JavaScript' 카테고리의 다른 글
Set 객체 (1) 2021.10.26 Date 생성자함수, 프로토타입 객체의 프로퍼티 (0) 2021.10.19 표준 빌트인 객체 Date (0) 2021.10.12 .filter().map()과 .reduce() (0) 2021.10.04 Array.prototype.sort() 메서드 (0) 2021.10.03