diff --git a/.changeset/cyan-tigers-sneeze.md b/.changeset/cyan-tigers-sneeze.md new file mode 100644 index 00000000..931532d6 --- /dev/null +++ b/.changeset/cyan-tigers-sneeze.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +feat: 문자열에서 한글을 추출해주는 extractHangul 함수를 제거합니다 diff --git a/.changeset/honest-roses-flow.md b/.changeset/honest-roses-flow.md new file mode 100644 index 00000000..b4a20c9c --- /dev/null +++ b/.changeset/honest-roses-flow.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +feat: hasBatchim 을 utils에서 별도 함수로 분리합니다. diff --git a/.changeset/kind-birds-provide.md b/.changeset/kind-birds-provide.md new file mode 100644 index 00000000..589c9a22 --- /dev/null +++ b/.changeset/kind-birds-provide.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +fix: 일관된 한글 이름 규칙 설정 함수명에서 꼭 필요하지 않다면 hangul이라는 워딩을 제거합니다 diff --git a/.changeset/late-beers-hang.md b/.changeset/late-beers-hang.md new file mode 100644 index 00000000..05bca1b0 --- /dev/null +++ b/.changeset/late-beers-hang.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +feat: disassembleHangul, disassemble, disassembleHangulToGroup 함수에서 hangul이라는 글자를 제거합니다 diff --git a/.changeset/mighty-paws-grow.md b/.changeset/mighty-paws-grow.md new file mode 100644 index 00000000..8f14ff4c --- /dev/null +++ b/.changeset/mighty-paws-grow.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +feat: choseongIncludes함수를 제거합니다. diff --git a/.changeset/pretty-apes-destroy.md b/.changeset/pretty-apes-destroy.md new file mode 100644 index 00000000..bbe3e536 --- /dev/null +++ b/.changeset/pretty-apes-destroy.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +canBeChoseong, canBeJungseong, canBeJongseong 을 utils에서 별도 함수로 분리합니다. diff --git a/.changeset/smooth-rings-mix.md b/.changeset/smooth-rings-mix.md new file mode 100644 index 00000000..3545a98d --- /dev/null +++ b/.changeset/smooth-rings-mix.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +hangulIncludes 함수를 제거합니다 diff --git a/.changeset/weak-walls-sniff.md b/.changeset/weak-walls-sniff.md new file mode 100644 index 00000000..975a6db5 --- /dev/null +++ b/.changeset/weak-walls-sniff.md @@ -0,0 +1,5 @@ +--- +"es-hangul": major +--- + +feat: 한글의 두음을 반환해주는 acronymizeHangul 함수를 제거합니다. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1bba496f..3a80ad0e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -74,4 +74,4 @@ import hangul from 'es-hangul' // hangul default export에 묶어서도 제공 hangul.getSimilarity(...) hangul.disassemble(...) hangul.josa(...) - +``` diff --git a/README-en_us.md b/README-en_us.md index a629726c..8173fb62 100644 --- a/README-en_us.md +++ b/README-en_us.md @@ -11,12 +11,16 @@ es-hangul is a library that makes it easy to handle [Hangul](https://en.wikipedi You can easily implement tasks related to Hangul, such as initial consonant search and attaching particles(josas). ```tsx -import { choseongIncludes } from 'es-hangul'; +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if (result === userInput) { + // do something +} ``` ```tsx diff --git a/README.md b/README.md index c91c9048..003f6dd5 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,19 @@ ## 사용 예시 -초성 검색, 조사 붙이기와 같은 한글 작업을 간단히 할 수 있습니다. +문자열 초성화, 조사 붙이기와 같은 한글 작업을 간단히 할 수 있습니다. ```tsx -import { choseongIncludes } from 'es-hangul'; +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if (result === userInput) { + // 일치한다면 if문이 실행 +} ``` ```tsx diff --git a/docs/src/components/demo/choseong-includes-demo.tsx b/docs/src/components/demo/choseong-includes-demo.tsx deleted file mode 100644 index faaf8c8c..00000000 --- a/docs/src/components/demo/choseong-includes-demo.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useState } from 'react'; -import { choseongIncludes } from 'es-hangul'; - -export function ChoseongIncludesDemo() { - const [searchWord, setSearchWord] = useState('홍길동'); - const [userInput, setUserInput] = useState('ㅎㄱㄷ'); - - const result = choseongIncludes(searchWord, userInput); - - return ( -
-
- - setSearchWord(e.target.value)} - className="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-300" - /> -
-
- - setUserInput(e.target.value)} - className="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-300" - /> -
- {result !== null && ( -

- Result: {result ? 'Match found' : 'No match'} -

- )} -
- ); -} diff --git a/docs/src/pages/docs/api/acronymizeHangul.en.mdx b/docs/src/pages/docs/api/acronymizeHangul.en.mdx deleted file mode 100644 index 9f2f9007..00000000 --- a/docs/src/pages/docs/api/acronymizeHangul.en.mdx +++ /dev/null @@ -1,16 +0,0 @@ -# acronymizeHangul - -It receives the Korean sentence and returns the first letter of that Korean sentence. -(We don't deal with non-Korean sentences; we don't deal with additional Korean + English sentences.) - -```typescript -function acronymizeHangul( - // String consisting of plural nouns (e.g. '버스 충전', '치킨과 맥주') - hangul: string -): string[]; -``` - -```typescript -acronymizeHangul('치킨과 맥주').join(''); //치맥 -acronymizeHangul('버스 충전 카드').join(''); //버충카 -``` diff --git a/docs/src/pages/docs/api/acronymizeHangul.ko.mdx b/docs/src/pages/docs/api/acronymizeHangul.ko.mdx deleted file mode 100644 index c1b576a4..00000000 --- a/docs/src/pages/docs/api/acronymizeHangul.ko.mdx +++ /dev/null @@ -1,16 +0,0 @@ -# acronymizeHangul - -한글 문장을 입력받아서, 해당 한글 문장의 첫글자를 리턴해줍니다. -(한글 문장이 아닌, 문장은 취급하지않습니다. 추가로 한글 문장 + 영어 문장의 경우에도 취급하지않습니다.) - -```typescript -function acronymizeHangul( - // 복수 명사로 이루어진 문자열 (e.g. '버스 충전', '치킨과 맥주') - hangul: string -): string[]; -``` - -```typescript -acronymizeHangul('치킨과 맥주').join(''); //치맥 -acronymizeHangul('버스 충전 카드').join(''); //버충카 -``` diff --git a/docs/src/pages/docs/api/canBe.en.md b/docs/src/pages/docs/api/canBe.en.md new file mode 100644 index 00000000..1338188f --- /dev/null +++ b/docs/src/pages/docs/api/canBe.en.md @@ -0,0 +1,53 @@ +--- +title: canBe +--- + +# canBeChoseong + +Check if a given character can be a choseong in Korean. + +```typescript +function canBeChoseong(character: string): boolean; +``` + +```typescript +canBeChoseong('ㄱ'); // true +canBeChoseong('ㅃ'); // true +canBeChoseong('ㄱㅅ'); // false +canBeChoseong('ㅏ'); // false +canBeChoseong('가'); // false +``` + +# canBeJungseong + +Check if a given character can be a jungseong in Korean. + +```typescript +function canBeJungseong(character: string): boolean; +``` + +```typescript +canBeJungseong('ㅏ'); // true +canBeJungseong('ㅗㅏ'); // true +canBeJungseong('ㅏㅗ'); // false +canBeJungseong('ㄱ'); // false +canBeJungseong('ㄱㅅ'); // false +canBeJungseong('가'); // false +``` + +# canBeJongseong + +Check if a given character can be a jongseong in Korean. + +```typescript +function canBeJongseong(character: string): boolean; +``` + +```typescript +canBeJongseong('ㄱ'); // true +canBeJongseong('ㄱㅅ'); // true +canBeJongseong('ㅎㄹ'); // false +canBeJongseong('가'); // false +canBeJongseong('ㅏ'); // false +canBeJongseong('ㅗㅏ'); // false +``` diff --git a/docs/src/pages/docs/api/canBe.ko.md b/docs/src/pages/docs/api/canBe.ko.md new file mode 100644 index 00000000..ede91e95 --- /dev/null +++ b/docs/src/pages/docs/api/canBe.ko.md @@ -0,0 +1,53 @@ +--- +title: canBe +--- + +# canBeChoseong + +인자로 받은 문자가 초성으로 위치할 수 있는 문자인지 검사합니다. + +```typescript +function canBeChoseong(character: string): boolean; +``` + +```typescript +canBeChoseong('ㄱ'); // true +canBeChoseong('ㅃ'); // true +canBeChoseong('ㄱㅅ'); // false +canBeChoseong('ㅏ'); // false +canBeChoseong('가'); // false +``` + +# canBeJungseong + +인자로 받은 문자가 중성으로 위치할 수 있는 문자인지 검사합니다. + +```typescript +function canBeJungseong(character: string): boolean; +``` + +```typescript +canBeJungseong('ㅏ'); // true +canBeJungseong('ㅗㅏ'); // true +canBeJungseong('ㅏㅗ'); // false +canBeJungseong('ㄱ'); // false +canBeJungseong('ㄱㅅ'); // false +canBeJungseong('가'); // false +``` + +# canBeJongseong + +인자로 받은 문자가 종성으로 위치할 수 있는 문자인지 검사합니다. + +```typescript +function canBeJongseong(character: string): boolean; +``` + +```typescript +canBeJongseong('ㄱ'); // true +canBeJongseong('ㄱㅅ'); // true +canBeJongseong('ㅎㄹ'); // false +canBeJongseong('가'); // false +canBeJongseong('ㅏ'); // false +canBeJongseong('ㅗㅏ'); // false +``` diff --git a/docs/src/pages/docs/api/choseongIncludes.en.mdx b/docs/src/pages/docs/api/choseongIncludes.en.mdx deleted file mode 100644 index 1daf7792..00000000 --- a/docs/src/pages/docs/api/choseongIncludes.en.mdx +++ /dev/null @@ -1,35 +0,0 @@ -import { Sandpack } from '@/components/Sandpack'; - -# choseongIncludes - -Performs a search for matches in the initial consonants of a string. - -```typescript -function choseongIncludes( - // The string to be checked for matching initial consonants (e.g., '프론트엔드') - x: string, - // Initial consonant string (e.g., 'ㅍㄹㅌㅇㄷ') - y: string -): boolean; -``` - -```typescript -choseongIncludes('프론트엔드', 'ㅍㄹㅌ'); // true -choseongIncludes('00프론트엔드', 'ㅍㄹㅌ'); // true -choseongIncludes('프론트엔드', 'ㅍㅌ'); // false -choseongIncludes('프론트엔드', '푸롴트'); // false -``` - -## Demo - -
- - - -```ts index.ts -import { choseongIncludes } from 'es-hangul'; - -console.log(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')); -``` - - diff --git a/docs/src/pages/docs/api/choseongIncludes.ko.mdx b/docs/src/pages/docs/api/choseongIncludes.ko.mdx deleted file mode 100644 index 509e9250..00000000 --- a/docs/src/pages/docs/api/choseongIncludes.ko.mdx +++ /dev/null @@ -1,35 +0,0 @@ -import { Sandpack } from '@/components/Sandpack'; - -# choseongIncludes - -문자열의 초성 일치 검색을 수행합니다. - -```typescript -function choseongIncludes( - // 초성 일치하는지 검사할 문자열 (e.g. '프론트엔드') - x: string, - // 초성 문자열 (e.g. 'ㅍㄹㅌㅇㄷ') - y: string -): boolean; -``` - -```typescript -choseongIncludes('프론트엔드', 'ㅍㄹㅌ'); // true -choseongIncludes('00프론트엔드', 'ㅍㄹㅌ'); // true -choseongIncludes('프론트엔드', 'ㅍㅌ'); // false -choseongIncludes('프론트엔드', '푸롴트'); // false -``` - -## 사용해보기 - -
- - - -```ts index.ts -import { choseongIncludes } from 'es-hangul'; - -console.log(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')); -``` - - diff --git a/docs/src/pages/docs/api/chosungIncludes.en.mdx b/docs/src/pages/docs/api/chosungIncludes.en.mdx deleted file mode 100644 index a635871b..00000000 --- a/docs/src/pages/docs/api/chosungIncludes.en.mdx +++ /dev/null @@ -1,35 +0,0 @@ -import { Sandpack } from '@/components/Sandpack'; - -# chosungIncludes (deprecated, Please use choseongIncludes) - -Performs a search for matches in the initial consonants of a string. - -```typescript -function chosungIncludes( - // The string to be checked for matching initial consonants (e.g., '프론트엔드') - x: string, - // Initial consonant string (e.g., 'ㅍㄹㅌㅇㄷ') - y: string -): boolean; -``` - -```typescript -chosungIncludes('프론트엔드', 'ㅍㄹㅌ'); // true -chosungIncludes('00프론트엔드', 'ㅍㄹㅌ'); // true -chosungIncludes('프론트엔드', 'ㅍㅌ'); // false -chosungIncludes('프론트엔드', '푸롴트'); // false -``` - -## Demo - -
- - - -```ts index.ts -import { choseongIncludes } from 'es-hangul'; - -console.log(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')); -``` - - diff --git a/docs/src/pages/docs/api/chosungIncludes.ko.mdx b/docs/src/pages/docs/api/chosungIncludes.ko.mdx deleted file mode 100644 index 9211e965..00000000 --- a/docs/src/pages/docs/api/chosungIncludes.ko.mdx +++ /dev/null @@ -1,35 +0,0 @@ -import { Sandpack } from '@/components/Sandpack'; - -# chosungIncludes (deprecated, choseongIncludes를 사용해주세요) - -문자열의 초성 일치 검색을 수행합니다. - -```typescript -function chosungIncludes( - // 초성 일치하는지 검사할 문자열 (e.g. '프론트엔드') - x: string, - // 초성 문자열 (e.g. 'ㅍㄹㅌㅇㄷ') - y: string -): boolean; -``` - -```typescript -chosungIncludes('프론트엔드', 'ㅍㄹㅌ'); // true -chosungIncludes('00프론트엔드', 'ㅍㄹㅌ'); // true -chosungIncludes('프론트엔드', 'ㅍㅌ'); // false -chosungIncludes('프론트엔드', '푸롴트'); // false -``` - -## 사용해보기 - -
- - - -```ts index.ts -import { choseongIncludes } from 'es-hangul'; - -console.log(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')); -``` - - diff --git a/docs/src/pages/docs/api/disassembleHangul.en.md b/docs/src/pages/docs/api/disassemble.en.md similarity index 52% rename from docs/src/pages/docs/api/disassembleHangul.en.md rename to docs/src/pages/docs/api/disassemble.en.md index 6cf2867f..66d499ce 100644 --- a/docs/src/pages/docs/api/disassembleHangul.en.md +++ b/docs/src/pages/docs/api/disassemble.en.md @@ -1,15 +1,15 @@ --- -title: disassembleHangul +title: disassemble --- -# disassembleHangul +# disassemble Completely separates a Hangul string into its individual characters by initial consonants, medial vowels, and final consonants, creating a single string. For detailed examples, see below. ```typescript -function disassembleHangul( +function disassemble( // The Korean string to be disassembled str: string ): string; @@ -18,8 +18,8 @@ function disassembleHangul( ## Examples ```tsx -disassembleHangul('값'); // 'ㄱㅏㅂㅅ' -disassembleHangul('값이 비싸다'); // 'ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ' -disassembleHangul('ㅘ'); // 'ㅗㅏ' -disassembleHangul('ㄵ'); // 'ㄴㅈ' +disassemble('값'); // 'ㄱㅏㅂㅅ' +disassemble('값이 비싸다'); // 'ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ' +disassemble('ㅘ'); // 'ㅗㅏ' +disassemble('ㄵ'); // 'ㄴㅈ' ``` diff --git a/docs/src/pages/docs/api/disassembleHangul.ko.md b/docs/src/pages/docs/api/disassemble.ko.md similarity index 51% rename from docs/src/pages/docs/api/disassembleHangul.ko.md rename to docs/src/pages/docs/api/disassemble.ko.md index 207b1c67..acc0d849 100644 --- a/docs/src/pages/docs/api/disassembleHangul.ko.md +++ b/docs/src/pages/docs/api/disassemble.ko.md @@ -1,15 +1,15 @@ --- -title: disassembleHangul +title: disassemble --- -# disassembleHangul +# disassemble 한글 문자열을 글자별로 초성/중성/종성 단위로 완전히 분리하여, 하나의 문자열로 만듭니다. 자세한 예시는 아래 Example을 참고하세요. ```typescript -function disassembleHangul( +function disassemble( // 분리할 한글 문자열 str: string ): string; @@ -18,8 +18,8 @@ function disassembleHangul( ## Examples ```tsx -disassembleHangul('값'); // 'ㄱㅏㅂㅅ' -disassembleHangul('값이 비싸다'); // 'ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ' -disassembleHangul('ㅘ'); // 'ㅗㅏ' -disassembleHangul('ㄵ'); // 'ㄴㅈ' +disassemble('값'); // 'ㄱㅏㅂㅅ' +disassemble('값이 비싸다'); // 'ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ' +disassemble('ㅘ'); // 'ㅗㅏ' +disassemble('ㄵ'); // 'ㄴㅈ' ``` diff --git a/docs/src/pages/docs/api/disassembleHangulToGroups.en.md b/docs/src/pages/docs/api/disassembleToGroups.en.md similarity index 62% rename from docs/src/pages/docs/api/disassembleHangulToGroups.en.md rename to docs/src/pages/docs/api/disassembleToGroups.en.md index 8485fba1..a52352e1 100644 --- a/docs/src/pages/docs/api/disassembleHangulToGroups.en.md +++ b/docs/src/pages/docs/api/disassembleToGroups.en.md @@ -1,8 +1,8 @@ --- -title: disassembleHangulToGroups +title: disassembleToGroups --- -# disassembleHangulToGroups +# disassembleToGroups Completely separate a Hangul string into individual characters based on the initial consonant, medial vowel, and final consonant. @@ -11,7 +11,7 @@ Complex consonants like `ㄵ` are split into `['ㄴ', 'ㅈ']`, and complex vowel For detailed examples, please refer to the section below. ```typescript -function disassembleHangulToGroups( +function disassembleToGroups( // The Korean string to be disassembled str: string ): string[][]; @@ -20,7 +20,7 @@ function disassembleHangulToGroups( ## Examples ```typescript -disassembleHangulToGroups('값'); // [['ㄱ', 'ㅏ', 'ㅂ', 'ㅅ']] -disassembleHangulToGroups('ㅘ'); // [['ㅗ', 'ㅏ']] -disassembleHangulToGroups('ㄵ'); // [['ㄴ', 'ㅈ']] +disassembleToGroups('사과'); // [['ㅅ', 'ㅏ'], ['ㄱ', 'ㅗ', 'ㅏ']] +disassembleToGroups('ㅘ'); // [['ㅗ', 'ㅏ']] +disassembleToGroups('ㄵ'); // [['ㄴ', 'ㅈ']] ``` diff --git a/docs/src/pages/docs/api/disassembleHangulToGroups.ko.md b/docs/src/pages/docs/api/disassembleToGroups.ko.md similarity index 59% rename from docs/src/pages/docs/api/disassembleHangulToGroups.ko.md rename to docs/src/pages/docs/api/disassembleToGroups.ko.md index 31b8d8d8..3106879f 100644 --- a/docs/src/pages/docs/api/disassembleHangulToGroups.ko.md +++ b/docs/src/pages/docs/api/disassembleToGroups.ko.md @@ -1,8 +1,8 @@ --- -title: disassembleHangulToGroups +title: disassembleToGroups --- -# disassembleHangulToGroups +# disassembleToGroups 한글 문자열을 글자별로 초성/중성/종성 단위로 완전히 분리합니다. @@ -11,7 +11,7 @@ title: disassembleHangulToGroups 자세한 예시는 아래 Example을 참고하세요. ```typescript -function disassembleHangulToGroups( +function disassembleToGroups( // 분리할 한글 문자열 str: string ): string[][]; @@ -20,7 +20,7 @@ function disassembleHangulToGroups( ## Examples ```typescript -disassembleHangulToGroups('값'); // [['ㄱ', 'ㅏ', 'ㅂ', 'ㅅ']] -disassembleHangulToGroups('ㅘ'); // [['ㅗ', 'ㅏ']] -disassembleHangulToGroups('ㄵ'); // [['ㄴ', 'ㅈ']] +disassembleToGroups('사과'); // [['ㅅ', 'ㅏ'], ['ㄱ', 'ㅗ', 'ㅏ']] +disassembleToGroups('ㅘ'); // [['ㅗ', 'ㅏ']] +disassembleToGroups('ㄵ'); // [['ㄴ', 'ㅈ']] ``` diff --git a/docs/src/pages/docs/api/extractHangul.en.md b/docs/src/pages/docs/api/extractHangul.en.md deleted file mode 100644 index c685c84a..00000000 --- a/docs/src/pages/docs/api/extractHangul.en.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: extractHangul ---- - -# extractHangul - -Extracts and returns only Korean characters from the string. - -For detailed examples, see below. - -```typescript -function extractHangul(str: string): string; -``` - -## Examples - -```tsx -extractHangul('안녕하세요1234abc'); // '안녕하세요' -extractHangul('abcde'); // '' -extractHangul('안녕하세요ㄱㄴ'); // '안녕하세요ㄱㄴ' -extractHangul('안녕하세요 만나서 반갑습니다'); // '안녕하세요 만나서 반갑습니다' -extractHangul('가나다!-29~라마바.,,사'); // '가나다라마바사' -``` diff --git a/docs/src/pages/docs/api/extractHangul.ko.md b/docs/src/pages/docs/api/extractHangul.ko.md deleted file mode 100644 index dc089bdb..00000000 --- a/docs/src/pages/docs/api/extractHangul.ko.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: extractHangul ---- - -# extractHangul - -문자열에서 한글만 추출하여 반환합니다. - -자세한 예시는 아래 Example을 참고하세요. - -```typescript -function extractHangul(str: string): string; -``` - -## Examples - -```tsx -extractHangul('안녕하세요1234abc'); // '안녕하세요' -extractHangul('abcde'); // '' -extractHangul('안녕하세요ㄱㄴ'); // '안녕하세요ㄱㄴ' -extractHangul('안녕하세요 만나서 반갑습니다'); // '안녕하세요 만나서 반갑습니다' -extractHangul('가나다!-29~라마바.,,사'); // '가나다라마바사' -``` diff --git a/docs/src/pages/docs/api/getChoseong.en.mdx b/docs/src/pages/docs/api/getChoseong.en.mdx new file mode 100644 index 00000000..3839acca --- /dev/null +++ b/docs/src/pages/docs/api/getChoseong.en.mdx @@ -0,0 +1,21 @@ +--- +title: getChoseong +--- + +# getChoseong + +Extracts the Choseong from a Korean word. (Example: 사과 -> 'ㅅㄱ') + +```typescript +function getChoseong( + // Korean string from which to extract the choseong + word: string +): string; +``` + +## Examples + +```tsx +getChoseong('사과'); // 'ㅅㄱ' +getChoseong('띄어 쓰기'); // 'ㄸㅇ ㅆㄱ' +``` diff --git a/docs/src/pages/docs/api/getChoseong.ko.mdx b/docs/src/pages/docs/api/getChoseong.ko.mdx new file mode 100644 index 00000000..8f10d84d --- /dev/null +++ b/docs/src/pages/docs/api/getChoseong.ko.mdx @@ -0,0 +1,23 @@ +--- +title: getChoseong +--- + +# getChoseong + +단어에서 초성을 추출합니다. (예: `사과` -> `'ㅅㄱ'`) + +자세한 예시는 아래 Example을 참고하세요. + +```typescript +function getChoseong( + // 초성을 추출 할 한글 문자열 + word: string +): string; +``` + +## Examples + +```tsx +getChoseong('사과'); // 'ㅅㄱ' +getChoseong('띄어 쓰기'); // 'ㄸㅇ ㅆㄱ' +``` diff --git a/docs/src/pages/docs/api/hangulIncludes.en.md b/docs/src/pages/docs/api/hangulIncludes.en.md deleted file mode 100644 index 80009d67..00000000 --- a/docs/src/pages/docs/api/hangulIncludes.en.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: hangulIncludes ---- - -# hangulIncludes - -Checks if a Hangul string contains another Hangul string. - -For example, `사과` contains `삭`, and `값이 비싸다` contains `갑` or `빘`. - -```typescript -function hangulIncludes( - // The string to be checked for containing the second argument y - x: string, - // The string to be checked for inclusion in the first argument x - y: string -): boolean; -``` - -## Examples - -```typescript -hangulIncludes('사과', ''); // true -hangulIncludes('사과', 'ㅅ'); // true -hangulIncludes('사과', '삭'); // true -hangulIncludes('사과', '삽'); // false -hangulIncludes('사과', '사과'); // true -``` diff --git a/docs/src/pages/docs/api/hangulIncludes.ko.md b/docs/src/pages/docs/api/hangulIncludes.ko.md deleted file mode 100644 index e80c7da6..00000000 --- a/docs/src/pages/docs/api/hangulIncludes.ko.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: hangulIncludes ---- - -# hangulIncludes - -한글 문자열이 다른 한글 문자열을 포함하는지 검사합니다. - -예를 들어서, `사과` 는 `삭` 을 포함하고, `값이 비싸다` 는 `갑` 또는 `빘`을 포함합니다. - -```typescript -function hangulIncludes( - // 두 번째 인자 y를 포함하는지 검사할 문자열 - x: string, - // 첫 번째 인자 x에 포함되는지 검사할 문자열 - y: string -): boolean; -``` - -## Examples - -```typescript -hangulIncludes('사과', ''); // true -hangulIncludes('사과', 'ㅅ'); // true -hangulIncludes('사과', '삭'); // true -hangulIncludes('사과', '삽'); // false -hangulIncludes('사과', '사과'); // true -``` diff --git a/docs/src/pages/docs/api/hasBatchim.en.mdx b/docs/src/pages/docs/api/hasBatchim.en.mdx new file mode 100644 index 00000000..c546d623 --- /dev/null +++ b/docs/src/pages/docs/api/hasBatchim.en.mdx @@ -0,0 +1,23 @@ +--- +title: hasBatchim +--- + +# hasBatchim + +Checks if the last character of a Korean string has a batchim (jongseong). + +````typescript +hasBatchim( + str: string, + options?: { only?: "single" | "double" } +): boolean + + + ```typescript + hasBatchim('값') // true + hasBatchim('토') // false + hasBatchim('갑', { only : "single" }) // true + hasBatchim('값', { only : "single" }) // false + hasBatchim('토', { only : "double" }) // false +```` + diff --git a/docs/src/pages/docs/api/hasBatchim.ko.mdx b/docs/src/pages/docs/api/hasBatchim.ko.mdx new file mode 100644 index 00000000..b5e6c20a --- /dev/null +++ b/docs/src/pages/docs/api/hasBatchim.ko.mdx @@ -0,0 +1,22 @@ +--- +title: hasBatchim +--- + +# hasBatchim + +한글 문자열의 마지막 글자가 받침이 있는지 확인합니다. + +````typescript +hasBatchim( + str: string, + options?: { only?: "single" | "double" } +): boolean + + + ```typescript + hasBatchim('값') // true + hasBatchim('토') // false + hasBatchim('갑', { only : "single" }) // true + hasBatchim('값', { only : "single" }) // false + hasBatchim('토', { only : "double" }) // false +```` diff --git a/docs/src/pages/docs/introduction.en.mdx b/docs/src/pages/docs/introduction.en.mdx index f4c78802..891c0844 100644 --- a/docs/src/pages/docs/introduction.en.mdx +++ b/docs/src/pages/docs/introduction.en.mdx @@ -32,31 +32,35 @@ Our library provides strong typing, allowing for easy detection of type errors d ### Full Support for Hangul-related Features -Our library provides a [modern API](./api/choseongIncludes) that can be conveniently used in various applications. +Our library provides a [modern API](./api/getChoseong) that can be conveniently used in various applications. -#### First Consonant Search ([choseongIncludes](./api/choseongIncludes)) +#### First Consonant Search ([getChoseong](./api/getChoseong)) -It checks whether an initial consonant is included in a specific word. For example, you can easily find out if the word '라면' (ramyeon) contains the initial consonants 'ㄹㅁ'. +It can get choseong from specific word. For example, you can easily find out if the word '라면' (ramyeon) contains the choseong 'ㄹㅁ'. -```tsx /choseongIncludes/ -import { choseongIncludes } from 'es-hangul'; +```tsx /getChoseong/ +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); -console.log(result); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if (result === userInput) { + // do something +} ``` -#### Disassembling Hangul Characters ([disassembleHangul](./api/disassembleHangul)) + +#### Disassembling Hangul Characters ([disassemble](./api/disassemble)) You can decompose a given Hangul string into initial consonants, vowels, and final consonants, and return it in array form to allow for more detailed analysis or modification of the string. -```tsx /disassembleHangul/ -import { disassembleHangul } from 'es-hangul'; +```tsx /disassemble/ +import { disassemble } from 'es-hangul'; const word = '안녕하세요'; -const disassembled = disassembleHangul(word); +const disassembled = disassemble(word); console.log(disassembled); // 'ㅇㅏㄴㄴㅕㅇㅎㅏㅅㅔㅇㅛ' ``` diff --git a/docs/src/pages/docs/introduction.ko.mdx b/docs/src/pages/docs/introduction.ko.mdx index fb3b3094..13c448de 100644 --- a/docs/src/pages/docs/introduction.ko.mdx +++ b/docs/src/pages/docs/introduction.ko.mdx @@ -32,31 +32,34 @@ ECMAScript Modules를 이용하여 사용하는 함수만 애플리케이션에 ### 한글을 위한 모든 인터페이스를 제공하는 것을 목표합니다 -다양한 애플리케이션에서 편리하게 사용할 수 있는 [현대적인 API](./api/choseongIncludes)를 제공합니다. +다양한 애플리케이션에서 편리하게 사용할 수 있는 [현대적인 API](./api/getChoseong)를 제공합니다. -#### 초성 검색 ([choseongIncludes](./api/choseongIncludes)) +#### 초성 검색 ([getChoseong](./api/getChoseong)) -초성이 특정 단어에 포함되어 있는지 검사합니다. 예를 들어, '라면'이라는 단어가 'ㄹㅁ'으로 시작하는 초성을 포함하는지 쉽게 알 수 있습니다. +특정 단어에서 초성을 얻을 수 있습니다. 예를 들어, '라면'이라는 단어가 'ㄹㅁ'으로 시작하는 초성을 포함하는지 쉽게 알 수 있습니다. -```tsx /choseongIncludes/ -import { choseongIncludes } from 'es-hangul'; +```tsx /getChoseong/ +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); -console.log(result); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if (result === userInput) { + // 일치한다면 if문이 실행 +} ``` -#### 초/중/종성 분해 ([disassembleHangul](./api/disassembleHangul)) +#### 초/중/종성 분해 ([disassemble](./api/disassemble)) 주어진 한글 문자열을 초성, 중성, 종성으로 분해하여 배열 형태로 반환해 문자열을 더 세밀하게 분석하거나 수정할 수 있습니다. -```tsx /disassembleHangul/ -import { disassembleHangul } from 'es-hangul'; +```tsx /disassemble/ +import { disassemble } from 'es-hangul'; const word = '안녕하세요'; -const disassembled = disassembleHangul(word); +const disassembled = disassemble(word); console.log(disassembled); // 'ㅇㅏㄴㄴㅕㅇㅎㅏㅅㅔㅇㅛ' ``` diff --git a/docs/src/pages/index.en.mdx b/docs/src/pages/index.en.mdx index 083f0d6c..0c26dffc 100644 --- a/docs/src/pages/index.en.mdx +++ b/docs/src/pages/index.en.mdx @@ -33,15 +33,19 @@ import { Callout, useTheme, Steps } from 'nextra-theme-docs'; ```tsx -import { choseongIncludes } from 'es-hangul'; +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); -console.log(result); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if(result === userInput){ + // do something +} ``` + ```tsx import { josa } from 'es-hangul'; diff --git a/docs/src/pages/index.ko.mdx b/docs/src/pages/index.ko.mdx index dffc4dec..03e8fb12 100644 --- a/docs/src/pages/index.ko.mdx +++ b/docs/src/pages/index.ko.mdx @@ -33,15 +33,19 @@ import { Callout, useTheme, Steps } from 'nextra-theme-docs'; ```tsx -import { choseongIncludes } from 'es-hangul'; +import { getChoseong } from 'es-hangul'; const searchWord = '라면'; const userInput = 'ㄹㅁ'; -const result = choseongIncludes(searchWord, userInput); -console.log(result); // true +const result = getChoseong(searchWord); // ㄹㅁ + +if(result === userInput){ + // 일치한다면 if문이 실행 +} ``` + ```tsx import { josa } from 'es-hangul'; diff --git a/src/_internal/hangul.spec.ts b/src/_internal/hangul.spec.ts index 684f9272..a2ce1c9f 100644 --- a/src/_internal/hangul.spec.ts +++ b/src/_internal/hangul.spec.ts @@ -1,6 +1,6 @@ import { - binaryAssembleHangulCharacters, - binaryAssembleHangul, + binaryAssembleCharacters, + binaryAssemble, isHangulAlphabet, isHangulCharacter, isHangul, @@ -72,102 +72,102 @@ describe('parse', () => { }); }); -describe('binaryAssembleHangulCharacters', () => { +describe('binaryAssembleCharacters', () => { it('초성과 중성만 조합', () => { - expect(binaryAssembleHangulCharacters('ㄱ', 'ㅏ')).toEqual('가'); + expect(binaryAssembleCharacters('ㄱ', 'ㅏ')).toEqual('가'); }); it('초성과 중성이 합쳐진 문자와 종성을 조합', () => { - expect(binaryAssembleHangulCharacters('가', 'ㅇ')).toEqual('강'); + expect(binaryAssembleCharacters('가', 'ㅇ')).toEqual('강'); }); it('초성과 중성과 종성이 합쳐진 문자와 자음을 조합하여 겹받침 만들기', () => { - expect(binaryAssembleHangulCharacters('갑', 'ㅅ')).toEqual('값'); + expect(binaryAssembleCharacters('갑', 'ㅅ')).toEqual('값'); }); it('초성과 중성이 합쳐진 문자와 모음을 조립하여 겹모음 만들기', () => { - expect(binaryAssembleHangulCharacters('고', 'ㅏ')).toEqual('과'); + expect(binaryAssembleCharacters('고', 'ㅏ')).toEqual('과'); }); it('초성과 중성(겹모음)이 합쳐진 문자와 자음을 조합', () => { - expect(binaryAssembleHangulCharacters('과', 'ㄱ')).toEqual('곽'); + expect(binaryAssembleCharacters('과', 'ㄱ')).toEqual('곽'); }); it('초성과 중성(겹모음)과 종성이 합쳐진 문자와 자음을 조합하여 겹받침 만들기', () => { - expect(binaryAssembleHangulCharacters('완', 'ㅈ')).toEqual('왅'); + expect(binaryAssembleCharacters('완', 'ㅈ')).toEqual('왅'); }); it('모음만 있는 문자와 모음을 조합하여 겹모음 만들기', () => { - expect(binaryAssembleHangulCharacters('ㅗ', 'ㅏ')).toEqual('ㅘ'); + expect(binaryAssembleCharacters('ㅗ', 'ㅏ')).toEqual('ㅘ'); }); it('초성과 중성과 종성이 합쳐진 문자의 연음 법칙', () => { - expect(binaryAssembleHangulCharacters('톳', 'ㅡ')).toEqual('토스'); + expect(binaryAssembleCharacters('톳', 'ㅡ')).toEqual('토스'); }); it('초성과 종성(겹모음)과 종성이 합쳐진 문자의 연음 법칙', () => { - expect(binaryAssembleHangulCharacters('왅', 'ㅓ')).toEqual('완저'); + expect(binaryAssembleCharacters('왅', 'ㅓ')).toEqual('완저'); }); it('초성과 중성과 종성(겹받침)이 합쳐진 문자의 연음 법칙', () => { - expect(binaryAssembleHangulCharacters('닭', 'ㅏ')).toEqual('달가'); - expect(binaryAssembleHangulCharacters('깎', 'ㅏ')).toEqual('까까'); + expect(binaryAssembleCharacters('닭', 'ㅏ')).toEqual('달가'); + expect(binaryAssembleCharacters('깎', 'ㅏ')).toEqual('까까'); }); it('문법에 맞지 않는 문자를 조합하면 단순 Join 한다. (문법 순서 틀림)', () => { - expect(binaryAssembleHangulCharacters('ㅏ', 'ㄱ')).toEqual('ㅏㄱ'); - expect(binaryAssembleHangulCharacters('까', 'ㅃ')).toEqual('까ㅃ'); - expect(binaryAssembleHangulCharacters('ㅘ', 'ㅏ')).toEqual('ㅘㅏ'); + expect(binaryAssembleCharacters('ㅏ', 'ㄱ')).toEqual('ㅏㄱ'); + expect(binaryAssembleCharacters('까', 'ㅃ')).toEqual('까ㅃ'); + expect(binaryAssembleCharacters('ㅘ', 'ㅏ')).toEqual('ㅘㅏ'); }); it('순서대로 입력했을 때 조합이 불가능한 문자라면 단순 Join 한다.', () => { - expect(binaryAssembleHangulCharacters('뼈', 'ㅣ')).toEqual('뼈ㅣ'); + expect(binaryAssembleCharacters('뼈', 'ㅣ')).toEqual('뼈ㅣ'); }); it('소스가 두 글자 이상이라면 Invalid source 에러를 발생시킨다.', () => { - expect(() => binaryAssembleHangulCharacters('가나', 'ㄴ')).toThrowError( + expect(() => binaryAssembleCharacters('가나', 'ㄴ')).toThrowError( 'Invalid source character: 가나. Source must be one character.' ); - expect(() => binaryAssembleHangulCharacters('ㄱㄴ', 'ㅏ')).toThrowError( + expect(() => binaryAssembleCharacters('ㄱㄴ', 'ㅏ')).toThrowError( 'Invalid source character: ㄱㄴ. Source must be one character.' ); }); it('다음 문자가 한글 문자 한 글자가 아니라면 Invalid next character 에러를 발생시킨다.', () => { assert.throws( - () => binaryAssembleHangulCharacters('ㄱ', 'a'), + () => binaryAssembleCharacters('ㄱ', 'a'), Error, 'Invalid next character: a. Next character must be one of the choseong, jungseong, or jongseong.' ); assert.throws( - () => binaryAssembleHangulCharacters('ㄱ', 'ㅡㅏ'), + () => binaryAssembleCharacters('ㄱ', 'ㅡㅏ'), Error, 'Invalid next character: ㅡㅏ. Next character must be one of the choseong, jungseong, or jongseong.' ); }); }); -describe('binaryAssembleHangul', () => { +describe('binaryAssemble', () => { it('문장과 모음을 조합하여 다음 글자를 생성한다.', () => { - expect(binaryAssembleHangul('저는 고양이를 좋아합닏', 'ㅏ')).toEqual('저는 고양이를 좋아합니다'); + expect(binaryAssemble('저는 고양이를 좋아합닏', 'ㅏ')).toEqual('저는 고양이를 좋아합니다'); }); it('문장과 자음을 조합하여 홑받침을 생성한다.', () => { - expect(binaryAssembleHangul('저는 고양이를 좋아하', 'ㅂ')).toEqual('저는 고양이를 좋아합'); + expect(binaryAssemble('저는 고양이를 좋아하', 'ㅂ')).toEqual('저는 고양이를 좋아합'); }); it('문장과 자음을 조합하여 겹받침을 생성한다.', () => { - expect(binaryAssembleHangul('저는 고양이를 좋아합', 'ㅅ')).toEqual('저는 고양이를 좋아핪'); + expect(binaryAssemble('저는 고양이를 좋아합', 'ㅅ')).toEqual('저는 고양이를 좋아핪'); }); it('조합이 불가능한 자음이 입력되면 단순 Join 한다.', () => { - expect(binaryAssembleHangul('저는 고양이를 좋아합', 'ㄲ')).toEqual('저는 고양이를 좋아합ㄲ'); - expect(binaryAssembleHangul('저는 고양이를 좋아합', 'ㅂ')).toEqual('저는 고양이를 좋아합ㅂ'); + expect(binaryAssemble('저는 고양이를 좋아합', 'ㄲ')).toEqual('저는 고양이를 좋아합ㄲ'); + expect(binaryAssemble('저는 고양이를 좋아합', 'ㅂ')).toEqual('저는 고양이를 좋아합ㅂ'); }); it('조합이 불가능한 모음이 입력되면 단순 Join 한다.', () => { - expect(binaryAssembleHangul('저는 고양이를 좋아하', 'ㅏ')).toEqual('저는 고양이를 좋아하ㅏ'); - expect(binaryAssembleHangul('저는 고양이를 좋아합니다', 'ㅜ')).toEqual('저는 고양이를 좋아합니다ㅜ'); + expect(binaryAssemble('저는 고양이를 좋아하', 'ㅏ')).toEqual('저는 고양이를 좋아하ㅏ'); + expect(binaryAssemble('저는 고양이를 좋아합니다', 'ㅜ')).toEqual('저는 고양이를 좋아합니다ㅜ'); }); describe('assertHangul', () => { diff --git a/src/_internal/hangul.ts b/src/_internal/hangul.ts index 882af421..9155e838 100644 --- a/src/_internal/hangul.ts +++ b/src/_internal/hangul.ts @@ -1,8 +1,9 @@ import assert, { excludeLastElement, isBlank, joinString } from '.'; -import { combineHangulCharacter, combineVowels, curriedCombineHangulCharacter } from '../combineHangulCharacter'; -import { disassembleHangulToGroups } from '../disassemble'; -import { removeLastHangulCharacter } from '../removeLastHangulCharacter'; -import { canBeChoseong, canBeJongseong, canBeJungseong, hasSingleBatchim } from '../utils'; +import { canBeChoseong, canBeJungseong, canBeJongseong } from '../canBe'; +import { combineCharacter, combineVowels, curriedCombineCharacter } from '../combineCharacter'; +import { disassembleToGroups } from '../disassemble'; +import { hasBatchim } from '../hasBatchim'; +import { removeLastCharacter } from '../removeLastCharacter'; export function isHangulCharacter(character: string) { return /^[가-힣]$/.test(character); @@ -47,23 +48,23 @@ export function safeParseHangul(actual: unknown): SafeParseSuccess | SafeParseEr } /** - * @name binaryAssembleHangulAlphabets + * @name binaryAssembleAlphabets * @description * 두 개의 한글 자모를 합칩니다. 완성된 한글 문자는 취급하지 않습니다. * @example * ``` - * binaryAssembleHangulAlphabets('ㄱ', 'ㅏ') // 가 - * binaryAssembleHangulAlphabets('ㅗ', 'ㅏ') // ㅘ + * binaryAssembleAlphabets('ㄱ', 'ㅏ') // 가 + * binaryAssembleAlphabets('ㅗ', 'ㅏ') // ㅘ * ``` */ -export function binaryAssembleHangulAlphabets(source: string, nextCharacter: string) { +export function binaryAssembleAlphabets(source: string, nextCharacter: string) { if (canBeJungseong(`${source}${nextCharacter}`)) { return combineVowels(source, nextCharacter); } const isConsonantSource = canBeJungseong(source) === false; if (isConsonantSource && canBeJungseong(nextCharacter)) { - return combineHangulCharacter(source, nextCharacter); + return combineCharacter(source, nextCharacter); } return joinString(source, nextCharacter); @@ -75,18 +76,18 @@ export function binaryAssembleHangulAlphabets(source: string, nextCharacter: str * 연음 법칙을 적용하여 두 개의 한글 문자를 연결합니다. */ export function linkHangulCharacters(source: string, nextCharacter: string) { - const sourceJamo = disassembleHangulToGroups(source)[0]; + const sourceJamo = disassembleToGroups(source)[0]; const [, lastJamo] = excludeLastElement(sourceJamo); - return joinString(removeLastHangulCharacter(source), combineHangulCharacter(lastJamo, nextCharacter)); + return joinString(removeLastCharacter(source), combineCharacter(lastJamo, nextCharacter)); } /** - * @name binaryAssembleHangulCharacters + * @name binaryAssembleCharacters * @description * 인자로 받은 한글 문자 2개를 합성합니다. * ```typescript - * binaryAssembleHangulCharacters( + * binaryAssembleCharacters( * // 소스 문자 * source: string * // 다음 문자 @@ -94,12 +95,12 @@ export function linkHangulCharacters(source: string, nextCharacter: string) { * ): string * ``` * @example - * binaryAssembleHangulCharacters('ㄱ', 'ㅏ') // 가 - * binaryAssembleHangulCharacters('가', 'ㅇ') // 강 - * binaryAssembleHangulCharacters('갑', 'ㅅ') // 값 - * binaryAssembleHangulCharacters('깎', 'ㅏ') // 까까 + * binaryAssembleCharacters('ㄱ', 'ㅏ') // 가 + * binaryAssembleCharacters('가', 'ㅇ') // 강 + * binaryAssembleCharacters('갑', 'ㅅ') // 값 + * binaryAssembleCharacters('깎', 'ㅏ') // 까까 */ -export function binaryAssembleHangulCharacters(source: string, nextCharacter: string) { +export function binaryAssembleCharacters(source: string, nextCharacter: string) { assert( isHangulCharacter(source) || isHangulAlphabet(source), `Invalid source character: ${source}. Source must be one character.` @@ -109,12 +110,12 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st `Invalid next character: ${nextCharacter}. Next character must be one of the choseong, jungseong, or jongseong.` ); - const sourceJamos = disassembleHangulToGroups(source)[0]; + const sourceJamos = disassembleToGroups(source)[0]; const isSingleCharacter = sourceJamos.length === 1; if (isSingleCharacter) { const sourceCharacter = sourceJamos[0]; - return binaryAssembleHangulAlphabets(sourceCharacter, nextCharacter); + return binaryAssembleAlphabets(sourceCharacter, nextCharacter); } const [restJamos, lastJamo] = excludeLastElement(sourceJamos); @@ -125,7 +126,7 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st return linkHangulCharacters(source, nextCharacter); } - const fixConsonant = curriedCombineHangulCharacter; + const fixConsonant = curriedCombineCharacter; const combineJungseong = fixConsonant(restJamos[0]); if (canBeJungseong(`${lastJamo}${nextCharacter}`)) { @@ -148,7 +149,12 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st const lastConsonant = lastJamo; - if (hasSingleBatchim(source) && canBeJongseong(`${lastConsonant}${nextCharacter}`)) { + if ( + hasBatchim(source, { + only: 'single', + }) && + canBeJongseong(`${lastConsonant}${nextCharacter}`) + ) { return combineJongseong(`${lastConsonant}${nextCharacter}`); } @@ -156,11 +162,11 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st } /** - * @name binaryAssembleHangul + * @name binaryAssemble * @description * 인자로 받은 한글 문장과 한글 문자 하나를 합성합니다. * ```typescript - * binaryAssembleHangul( + * binaryAssemble( * // 한글 문장 * source: string * // 한글 문자 @@ -168,18 +174,16 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st * ): string * ``` * @example - * binaryAssembleHangul('저는 고양이를 좋아합닏', 'ㅏ') // 저는 고양이를 좋아합니다 - * binaryAssembleHangul('저는 고양이를 좋아합', 'ㅅ') // 저는 고양이를 좋아핪 - * binaryAssembleHangul('저는 고양이를 좋아하', 'ㅏ') // 저는 고양이를 좋아하ㅏ + * binaryAssemble('저는 고양이를 좋아합닏', 'ㅏ') // 저는 고양이를 좋아합니다 + * binaryAssemble('저는 고양이를 좋아합', 'ㅅ') // 저는 고양이를 좋아핪 + * binaryAssemble('저는 고양이를 좋아하', 'ㅏ') // 저는 고양이를 좋아하ㅏ */ -export function binaryAssembleHangul(source: string, nextCharacter: string) { +export function binaryAssemble(source: string, nextCharacter: string) { const [rest, lastCharacter] = excludeLastElement(source.split('')); const needJoinString = isBlank(lastCharacter) || isBlank(nextCharacter); return joinString( ...rest, - needJoinString - ? joinString(lastCharacter, nextCharacter) - : binaryAssembleHangulCharacters(lastCharacter, nextCharacter) + needJoinString ? joinString(lastCharacter, nextCharacter) : binaryAssembleCharacters(lastCharacter, nextCharacter) ); } diff --git a/src/_internal/index.spec.ts b/src/_internal/index.spec.ts index 6c6bc393..e2e02b6c 100644 --- a/src/_internal/index.spec.ts +++ b/src/_internal/index.spec.ts @@ -1,4 +1,4 @@ -import assert, { excludeLastElement, isBlank, joinString } from './index'; +import assert, { excludeLastElement, hasProperty, hasValueInReadOnlyStringList, isBlank, joinString } from './index'; describe('excludeLastElement', () => { it('마지막 요소를 제외한 모든 요소와 마지막 요소를 반환한다', () => { @@ -59,3 +59,55 @@ describe('assert', () => { expect(() => assert(false, customMessage)).toThrowError(customMessage); }); }); + +describe('hasValueInReadOnlyStringList', () => { + const testReadonlyList = ['ㄱ', 'ㄴ', 'ㄷ'] as const; + + it('read-only 문자열 리스트에 요소가 존재한다면 true를 반환한다.', () => { + const testValue = 'ㄱ'; + + expect(hasValueInReadOnlyStringList(testReadonlyList, testValue)).toBeTruthy(); + }); + + it('read-only 문자열 리스트에 요소가 존재하지 않으면 false를 반환한다.', () => { + const testValue = 'ㄹ'; + + expect(hasValueInReadOnlyStringList(testReadonlyList, testValue)).toBeFalsy(); + }); + + it('read-only 문자열 리스트에 요소가 존재한다면 두 번째 인자의 타입을 좁힌다.', () => { + const testValue = 'ㄱ' as string; + + if (hasValueInReadOnlyStringList(testReadonlyList, testValue)) { + expectTypeOf(testValue).toEqualTypeOf<'ㄱ' | 'ㄴ' | 'ㄷ'>(); + } else { + expectTypeOf(testValue).toEqualTypeOf(); + } + }); +}); + +describe('hasProperty', () => { + const testObj = { ㄱ: 'ㄱ', ㄴ: 'ㄴ', ㄷ: 'ㄷ' } as const; + + it('객체에 속성이 존재하면 true를 반환한다.', () => { + const testKey = 'ㄱ'; + + expect(hasProperty(testObj, testKey)).toBeTruthy(); + }); + + it('객체에 속성이 존재하지 않으면 false를 반환한다.', () => { + const testKey = 'ㄹ'; + + expect(hasProperty(testObj, testKey)).toBeFalsy(); + }); + + it('객체에 속성이 존재한다면 두 번째 인자의 타입을 좁힌다.', () => { + const testKey = 'ㄱ' as string; + + if (hasProperty(testObj, testKey)) { + expectTypeOf(testKey).toEqualTypeOf<'ㄱ' | 'ㄴ' | 'ㄷ'>(); + } else { + expectTypeOf(testKey).toEqualTypeOf(); + } + }); +}); diff --git a/src/_internal/index.ts b/src/_internal/index.ts index 4020b7b2..fa05d5b0 100644 --- a/src/_internal/index.ts +++ b/src/_internal/index.ts @@ -30,3 +30,11 @@ export function defined(value: T | undefined): T { export function arrayIncludes(array: Type[] | readonly Type[], item: unknown, fromIndex?: number): item is Type { return array.includes(item as Type, fromIndex); } + +export function hasValueInReadOnlyStringList(list: readonly T[], value: string): value is T { + return list.some(item => item === value); +} + +export function hasProperty(obj: T, key: K): key is K & keyof T { + return Object.prototype.hasOwnProperty.call(obj, key); +} diff --git a/src/acronymizeHangul.spec.ts b/src/acronymizeHangul.spec.ts deleted file mode 100644 index a4d8b91e..00000000 --- a/src/acronymizeHangul.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { acronymizeHangul } from './acronymizeHangul'; - -describe('acronymizeHangul', () => { - it('한글 문장 단어중 첫 문자만 뽑은 리스트를 반환', () => { - expect(acronymizeHangul('치킨과 맥주')).toHaveLength(2); - expect(acronymizeHangul('치킨과 맥주').join('')).toBe('치맥'); - - expect(acronymizeHangul('버스 충전 카드')).toHaveLength(3); - expect(acronymizeHangul('버스 충전 카드').join('')).toBe('버충카'); - }); - it('한글이 아닌 문장 넣었을 때', () => { - expect(() => acronymizeHangul('test test')).toThrowError('"test test" is not a valid hangul string'); - }); - - it('한글과 영어가 섞인 문장을 넣었을 때', () => { - expect(() => acronymizeHangul('고기와 Cheese')).toThrowError('"고기와 Cheese" is not a valid hangul string'); - }); -}); diff --git a/src/acronymizeHangul.ts b/src/acronymizeHangul.ts deleted file mode 100644 index 9103ec40..00000000 --- a/src/acronymizeHangul.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { parseHangul } from './_internal/hangul'; - -/** - * - * @param getHangulAcronym - * @description - * 한글 문장을 입력받아서, 해당 한글 문장의 초성을을 리턴해줍니다. - * 한글 문장이 아닌, 문장은 취급하지않습니다. 추가로 한글 문장 + 영어 문장의 경우에도 취급하지않습니다. - */ -export function acronymizeHangul(hangul: string) { -return parseHangul(hangul).split(' ').map(word => word.charAt(0)); -} diff --git a/src/assemble.spec.ts b/src/assemble.spec.ts index 831a698b..2c4448c5 100644 --- a/src/assemble.spec.ts +++ b/src/assemble.spec.ts @@ -1,13 +1,13 @@ -import { assembleHangul } from './assemble'; +import { assemble } from './assemble'; -describe('assembleHangul', () => { +describe('assemble', () => { it('온전한 한글과 한글 문자 조합', () => { - expect(assembleHangul(['아버지가', ' ', '방ㅇ', 'ㅔ ', '들ㅇ', 'ㅓ갑니다'])).toEqual('아버지가 방에 들어갑니다'); + expect(assemble(['아버지가', ' ', '방ㅇ', 'ㅔ ', '들ㅇ', 'ㅓ갑니다'])).toEqual('아버지가 방에 들어갑니다'); }); it('온전한 한글만 조합', () => { - expect(assembleHangul(['아버지가', ' ', '방에 ', '들어갑니다'])).toEqual('아버지가 방에 들어갑니다'); + expect(assemble(['아버지가', ' ', '방에 ', '들어갑니다'])).toEqual('아버지가 방에 들어갑니다'); }); it('온전하지 않은 한글만 조합', () => { - expect(assembleHangul(['ㅇ', 'ㅏ', 'ㅂ', 'ㅓ', 'ㅈ', 'ㅣ'])).toEqual('아버지'); + expect(assemble(['ㅇ', 'ㅏ', 'ㅂ', 'ㅓ', 'ㅈ', 'ㅣ'])).toEqual('아버지'); }); }); diff --git a/src/assemble.ts b/src/assemble.ts index ced978aa..66ebbf06 100644 --- a/src/assemble.ts +++ b/src/assemble.ts @@ -1,22 +1,22 @@ -import { disassembleHangul } from './disassemble'; -import { binaryAssembleHangul } from './_internal/hangul'; +import { disassemble } from './disassemble'; +import { binaryAssemble } from './_internal/hangul'; /** - * @name assembleHangul + * @name assemble * @description * 인자로 받은 배열에 담긴 한글 문장과 문자를 한글 규칙에 맞게 합성합니다. * ```typescript - * assembleHangul( + * assemble( * // 한글 문자와 문장을 담고 있는 배열 * words: string[] * ): string * ``` * @example - * assembleHangul(['아버지가', ' ', '방ㅇ', 'ㅔ ', '들ㅇ', 'ㅓ갑니다']) // 아버지가 방에 들어갑니다 - * assembleHangul(['아버지가', ' ', '방에 ', '들어갑니다']) // 아버지가 방에 들어갑니다 - * assembleHangul(['ㅇ', 'ㅏ', 'ㅂ', 'ㅓ', 'ㅈ', 'ㅣ']) // 아버지 + * assemble(['아버지가', ' ', '방ㅇ', 'ㅔ ', '들ㅇ', 'ㅓ갑니다']) // 아버지가 방에 들어갑니다 + * assemble(['아버지가', ' ', '방에 ', '들어갑니다']) // 아버지가 방에 들어갑니다 + * assemble(['ㅇ', 'ㅏ', 'ㅂ', 'ㅓ', 'ㅈ', 'ㅣ']) // 아버지 */ -export function assembleHangul(words: string[]) { - const disassembled = disassembleHangul(words.join('')).split(''); - return disassembled.reduce(binaryAssembleHangul); +export function assemble(words: string[]) { + const disassembled = disassemble(words.join('')).split(''); + return disassembled.reduce(binaryAssemble); } diff --git a/src/canBe.spec.ts b/src/canBe.spec.ts new file mode 100644 index 00000000..1ace262d --- /dev/null +++ b/src/canBe.spec.ts @@ -0,0 +1,79 @@ +import { canBeChoseong, canBeJongseong, canBeJungseong } from './canBe'; + +describe('canBeChoseong', () => { + describe('초성이 될 수 있다고 판단되는 경우', () => { + it('ㄱ', () => { + expect(canBeChoseong('ㄱ')).toBe(true); + }); + it('ㅃ', () => { + expect(canBeChoseong('ㅃ')).toBe(true); + }); + }); + + describe('초성이 될 수 없다고 판단되는 경우', () => { + it('ㅏ', () => { + expect(canBeChoseong('ㅏ')).toBe(false); + }); + it('ㅘ', () => { + expect(canBeChoseong('ㅘ')).toBe(false); + }); + it('ㄱㅅ', () => { + expect(canBeChoseong('ㄱㅅ')).toBe(false); + }); + it('가', () => { + expect(canBeChoseong('가')).toBe(false); + }); + }); +}); + +describe('canBeJungseong', () => { + describe('중성이 될 수 있다고 판단되는 경우', () => { + it('ㅗㅏ', () => { + expect(canBeJungseong('ㅗㅏ')).toBe(true); + }); + it('ㅏ', () => { + expect(canBeJungseong('ㅏ')).toBe(true); + }); + }); + + describe('중성이 될 수 없다고 판단되는 경우', () => { + it('ㄱ', () => { + expect(canBeJungseong('ㄱ')).toBe(false); + }); + it('ㄱㅅ', () => { + expect(canBeJungseong('ㄱㅅ')).toBe(false); + }); + it('가', () => { + expect(canBeJungseong('가')).toBe(false); + }); + }); +}); + +describe('canBeJongseong', () => { + describe('종성이 될 수 있다고 판단되는 경우', () => { + it('ㄱ', () => { + expect(canBeJongseong('ㄱ')).toBe(true); + }); + it('ㄱㅅ', () => { + expect(canBeJongseong('ㄱㅅ')).toBe(true); + }); + it('ㅂㅅ', () => { + expect(canBeJongseong('ㅂㅅ')).toBe(true); + }); + }); + + describe('종성이 될 수 없다고 판단되는 경우', () => { + it('ㅎㄹ', () => { + expect(canBeJongseong('ㅎㄹ')).toBe(false); + }); + it('ㅗㅏ', () => { + expect(canBeJongseong('ㅗㅏ')).toBe(false); + }); + it('ㅏ', () => { + expect(canBeJongseong('ㅏ')).toBe(false); + }); + it('가', () => { + expect(canBeJongseong('ㅏ')).toBe(false); + }); + }); +}); diff --git a/src/canBe.ts b/src/canBe.ts new file mode 100644 index 00000000..0e8d7b05 --- /dev/null +++ b/src/canBe.ts @@ -0,0 +1,71 @@ +import { hasValueInReadOnlyStringList } from './_internal'; +import { + HANGUL_CHARACTERS_BY_FIRST_INDEX, + HANGUL_CHARACTERS_BY_LAST_INDEX, + HANGUL_CHARACTERS_BY_MIDDLE_INDEX, +} from './constants'; + +/** + * @name canBeChoseong + * @description + * 인자로 받은 문자가 초성으로 위치할 수 있는 문자인지 검사합니다. + * ```typescript + * canBeChoseong( + * // 대상 문자 + * character: string + * ): boolean + * ``` + * @example + * canBeChoseong('ㄱ') // true + * canBeChoseong('ㅃ') // true + * canBeChoseong('ㄱㅅ') // false + * canBeChoseong('ㅏ') // false + * canBeChoseong('가') // false + */ +export function canBeChoseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_FIRST_INDEX)[number] { + return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_FIRST_INDEX, character); +} + +/** + * @name canBeJungseong + * @description + * 인자로 받은 문자가 중성으로 위치할 수 있는 문자인지 검사합니다. + * ```typescript + * canBeJungseong( + * // 대상 문자 + * character: string + * ): boolean + * ``` + * @example + * canBeJungseong('ㅏ') // true + * canBeJungseong('ㅗㅏ') // true + * canBeJungseong('ㅏㅗ') // false + * canBeJungseong('ㄱ') // false + * canBeJungseong('ㄱㅅ') // false + * canBeJungseong('가') // false + */ +export function canBeJungseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_MIDDLE_INDEX)[number] { + return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_MIDDLE_INDEX, character); +} + +/** + * @name canBeJongseong + * @description + * 인자로 받은 문자가 종성으로 위치할 수 있는 문자인지 검사합니다. + * ```typescript + * canBeJongseong( + * // 대상 문자 + * character: string + * ): boolean + * ``` + * @example + * canBeJongseong('ㄱ') // true + * canBeJongseong('ㄱㅅ') // true + * canBeJongseong('ㅎㄹ') // false + * canBeJongseong('가') // false + * canBeJongseong('ㅏ') // false + * canBeJongseong('ㅗㅏ') // false + */ +export function canBeJongseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_LAST_INDEX)[number] { + return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_LAST_INDEX, character); +} diff --git a/src/choseongIncludes.spec.ts b/src/choseongIncludes.spec.ts deleted file mode 100644 index 245b891f..00000000 --- a/src/choseongIncludes.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { choseongIncludes } from './choseongIncludes'; - -describe('choseongIncludes', () => { - describe('초성이 포함되어있다고 판단되는 경우', () => { - it('"ㅍㄹㅌ" 문자열로 "프론트엔드"를 검색하면 true를 반환한다.', () => { - expect(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')).toBe(true); - }); - - it('"ㅍㄹㅌ" 문자열로 "00프론트엔드"를 검색하면 true를 반환한다.', () => { - expect(choseongIncludes('00프론트엔드', 'ㅍㄹㅌ')).toBe(true); - }); - - it('"ㅍㄹㅌㅇㄷㄱㅂㅈ" 문자열로 "프론트엔드 개발자"를 검색하면 true를 반환한다.', () => { - expect(choseongIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷㄱㅂㅈ')).toBe(true); - }); - - it('"ㅍㄹㅌㅇㄷ ㄱㅂㅈ" 문자열로 "프론트엔드 개발자"를 검색하면 true를 반환한다.', () => { - expect(choseongIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷ ㄱㅂㅈ')).toBe(true); - }); - }); - - describe('초성이 포함되어있다고 판단되지 않는 경우', () => { - it('"ㅍㅌ" 문자열로 "프론트엔드"를 검색하면 false를 반환한다.', () => { - expect(choseongIncludes('프론트엔드', 'ㅍㅌ')).toBe(false); - }); - - it('빈 문자열로 "프론트엔드 개발자"를 검색하면 false를 반환한다.', () => { - expect(choseongIncludes('프론트엔드 개발자', ' ')).toBe(false); - }); - - it('"푸롴트" 문자열로 "프론트엔드"를 검색하면 초성으로만 구성되어 있지 않아 false를 반환한다.', () => { - expect(choseongIncludes('프론트엔드', '푸롴트')).toBe(false); - }); - }); -}); diff --git a/src/choseongIncludes.ts b/src/choseongIncludes.ts deleted file mode 100644 index 3dee936b..00000000 --- a/src/choseongIncludes.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { disassembleHangulToGroups } from './disassemble'; -import { canBeChoseong, getChoseong } from './utils'; - -export function choseongIncludes(x: string, y: string) { - const trimmedY = y.replace(/\s/g, ''); - - if (!isOnlyChoseong(trimmedY)) { - return false; - } - - const choseongX = getChoseong(x).replace(/\s/g, ''); - const choseongY = trimmedY; - - return choseongX.includes(choseongY); -} - -/* - * @description 문자열이 한글초성으로만 주어진 경우 - */ -export function isOnlyChoseong(str: string) { - const groups = disassembleHangulToGroups(str); - if (groups.length === 0) { - return false; - } - - return groups.every(disassembled => { - return disassembled.length === 1 && canBeChoseong(disassembled[0]); - }); -} diff --git a/src/chosungIncludes.ts b/src/chosungIncludes.ts deleted file mode 100644 index 3c8f0ec1..00000000 --- a/src/chosungIncludes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isOnlyChoseong } from './choseongIncludes'; -import { getChoseong } from './utils'; - -/** - * @deprecated choseongIncludes를 사용해 주세요. - */ -export function chosungIncludes(x: string, y: string) { - const trimmedY = y.replace(/\s+/g, ''); - - if (!isOnlyChoseong(trimmedY)) { - return false; - } - - const choseongX = getChoseong(x).replace(/\s/g, ''); - const choseongY = trimmedY; - - return choseongX.includes(choseongY); -} diff --git a/src/combineHangulCharacter.spec.ts b/src/combineCharacter.spec.ts similarity index 66% rename from src/combineHangulCharacter.spec.ts rename to src/combineCharacter.spec.ts index 5bd0845c..1e7e4f24 100644 --- a/src/combineHangulCharacter.spec.ts +++ b/src/combineCharacter.spec.ts @@ -1,32 +1,32 @@ -import { combineHangulCharacter, combineVowels } from './combineHangulCharacter'; +import { combineCharacter, combineVowels } from './combineCharacter'; -describe('combineHangulCharacter', () => { +describe('combineCharacter', () => { it('종성으로 겹받침으로 구성될 수 있는 문자 두 개를 받으면 겹받침을 생성한다. (ㄱ, ㅏ, ㅂㅅ)', () => { - expect(combineHangulCharacter('ㄱ', 'ㅏ', 'ㅂㅅ')).toEqual('값'); + expect(combineCharacter('ㄱ', 'ㅏ', 'ㅂㅅ')).toEqual('값'); }); it('종성이 입력되지 않았다면 받침이 없는 문자로 합성한다. (ㅌ, ㅗ)', () => { - expect(combineHangulCharacter('ㅌ', 'ㅗ')).toEqual('토'); + expect(combineCharacter('ㅌ', 'ㅗ')).toEqual('토'); }); it('종성이 입력되었다면 받침을 추가한다. (ㅌ, ㅗ, ㅅ)', () => { - expect(combineHangulCharacter('ㅌ', 'ㅗ', 'ㅅ')).toEqual('톳'); + expect(combineCharacter('ㅌ', 'ㅗ', 'ㅅ')).toEqual('톳'); }); it('초성이 될 수 없는 문자가 초성으로 입력되면 에러를 반환한다. (ㅏ, ㅏ, ㄱ)', () => { - expect(() => combineHangulCharacter('ㅏ', 'ㅏ', 'ㄱ')).toThrowError('Invalid hangul Characters: ㅏ, ㅏ, ㄱ'); + expect(() => combineCharacter('ㅏ', 'ㅏ', 'ㄱ')).toThrowError('Invalid hangul Characters: ㅏ, ㅏ, ㄱ'); }); it('중성이 될 수 없는 문자가 중성으로 입력되면 에러를 반환한다. (ㄱ, ㄴ, ㅃ)', () => { - expect(() => combineHangulCharacter('ㄱ', 'ㄴ', 'ㅃ')).toThrowError('Invalid hangul Characters: ㄱ, ㄴ, ㅃ'); + expect(() => combineCharacter('ㄱ', 'ㄴ', 'ㅃ')).toThrowError('Invalid hangul Characters: ㄱ, ㄴ, ㅃ'); }); it('종성이 될 수 없는 문자가 종성으로 입력되면 에러를 반환한다. (ㄱ, ㅏ, ㅃ)', () => { - expect(() => combineHangulCharacter('ㄱ', 'ㅏ', 'ㅃ')).toThrowError('Invalid hangul Characters: ㄱ, ㅏ, ㅃ'); + expect(() => combineCharacter('ㄱ', 'ㅏ', 'ㅃ')).toThrowError('Invalid hangul Characters: ㄱ, ㅏ, ㅃ'); }); it('온전한 한글 문자가 하나라도 입력되면 에러를 반환한다. (가, ㅏ, ㄱ)', () => { - expect(() => combineHangulCharacter('가', 'ㅏ', 'ㄱ')).toThrowError('Invalid hangul Characters: 가, ㅏ, ㄱ'); + expect(() => combineCharacter('가', 'ㅏ', 'ㄱ')).toThrowError('Invalid hangul Characters: 가, ㅏ, ㄱ'); }); }); diff --git a/src/combineHangulCharacter.ts b/src/combineCharacter.ts similarity index 81% rename from src/combineHangulCharacter.ts rename to src/combineCharacter.ts index 7ace284c..762d8145 100644 --- a/src/combineHangulCharacter.ts +++ b/src/combineCharacter.ts @@ -1,3 +1,4 @@ +import { canBeChoseong, canBeJongseong, canBeJungseong } from './canBe'; import { COMPLETE_HANGUL_START_CHARCODE, DISASSEMBLED_VOWELS_BY_VOWEL, @@ -5,14 +6,13 @@ import { HANGUL_CHARACTERS_BY_LAST_INDEX, HANGUL_CHARACTERS_BY_MIDDLE_INDEX, } from './constants'; -import { canBeChoseong, canBeJongseong, canBeJungseong } from './utils'; /** - * @name combineHangulCharacter + * @name combineCharacter * @description * 인자로 초성, 중성, 종성을 받아 하나의 한글 문자를 반환합니다. * ```typescript - * combineHangulCharacter( + * combineCharacter( * // 초성 * firstCharacter: string * // 중성 @@ -22,10 +22,10 @@ import { canBeChoseong, canBeJongseong, canBeJungseong } from './utils'; * ): string * ``` * @example - * combineHangulCharacter('ㄱ', 'ㅏ', 'ㅂㅅ') // '값' - * combineHangulCharacter('ㅌ', 'ㅗ') // '토' + * combineCharacter('ㄱ', 'ㅏ', 'ㅂㅅ') // '값' + * combineCharacter('ㅌ', 'ㅗ') // '토' */ -export function combineHangulCharacter(firstCharacter: string, middleCharacter: string, lastCharacter = '') { +export function combineCharacter(firstCharacter: string, middleCharacter: string, lastCharacter = '') { if ( canBeChoseong(firstCharacter) === false || canBeJungseong(middleCharacter) === false || @@ -51,19 +51,19 @@ export function combineHangulCharacter(firstCharacter: string, middleCharacter: } /** - * @name curriedCombineHangulCharacter + * @name curriedCombineCharacter * @description - * 인자로 초성, 중성, 종성을 받아 하나의 한글 문자를 반환하는 `combineHangulCharacter` 함수의 커링된 버전입니다. + * 인자로 초성, 중성, 종성을 받아 하나의 한글 문자를 반환하는 `combineCharacter` 함수의 커링된 버전입니다. * @example - * const combineMiddleHangulCharacter = curriedCombineHangulCharacter('ㄱ') + * const combineMiddleHangulCharacter = curriedCombineCharacter('ㄱ') * const combineLastHangulCharacter = combineMiddleHangulCharacter('ㅏ') * combineLastHangulCharacter('ㄱ') // '각' */ -export const curriedCombineHangulCharacter = +export const curriedCombineCharacter = (firstCharacter: string) => (middleCharacter: string) => (lastCharacter = '') => - combineHangulCharacter(firstCharacter, middleCharacter, lastCharacter); + combineCharacter(firstCharacter, middleCharacter, lastCharacter); /** * @name combineVowels diff --git a/src/convertQwertyToHangulAlphabet.spec.ts b/src/convertQwertyToAlphabet.spec.ts similarity index 68% rename from src/convertQwertyToHangulAlphabet.spec.ts rename to src/convertQwertyToAlphabet.spec.ts index 0130e75f..07e1cf2d 100644 --- a/src/convertQwertyToHangulAlphabet.spec.ts +++ b/src/convertQwertyToAlphabet.spec.ts @@ -1,33 +1,33 @@ -import { convertQwertyToHangul, convertQwertyToHangulAlphabet } from './convertQwertyToHangulAlphabet'; +import { convertQwertyToHangul, convertQwertyToAlphabet } from './convertQwertyToAlphabet'; -describe('convertQwertyToHangulAlphabet', () => { +describe('convertQwertyToAlphabet', () => { it('영어 알파벳을 한글 음소로 바꾼다.', () => { - expect(convertQwertyToHangulAlphabet('abc')).toBe('ㅁㅠㅊ'); + expect(convertQwertyToAlphabet('abc')).toBe('ㅁㅠㅊ'); }); it('쌍/자모음에 대응하지 않는 영어 알파벳을 한글 음소로 바꾼다.', () => { - expect(convertQwertyToHangulAlphabet('ABC')).toBe('ㅁㅠㅊ'); + expect(convertQwertyToAlphabet('ABC')).toBe('ㅁㅠㅊ'); }); it('영어 알파벳은 한글 음소로 바꾸고, 한글 음절은 유지한다.', () => { - expect(convertQwertyToHangulAlphabet('vm론트')).toBe('ㅍㅡ론트'); + expect(convertQwertyToAlphabet('vm론트')).toBe('ㅍㅡ론트'); }); it('분해된 한글 음소는 유지한다.', () => { - expect(convertQwertyToHangulAlphabet('ㅍㅡㄹㅗㄴㅌㅡ')).toBe('ㅍㅡㄹㅗㄴㅌㅡ'); + expect(convertQwertyToAlphabet('ㅍㅡㄹㅗㄴㅌㅡ')).toBe('ㅍㅡㄹㅗㄴㅌㅡ'); }); it('영어 알파벳이 아닌 입력은 유지한다.', () => { - expect(convertQwertyToHangulAlphabet('4월/20dlf!')).toBe('4월/20ㅇㅣㄹ!'); + expect(convertQwertyToAlphabet('4월/20dlf!')).toBe('4월/20ㅇㅣㄹ!'); }); it('영문 대문자는 쌍자/모음으로 바꾼다.', () => { - expect(convertQwertyToHangulAlphabet('RㅏㄱEㅜrl')).toBe('ㄲㅏㄱㄸㅜㄱㅣ'); - expect(convertQwertyToHangulAlphabet('ㅇPdml')).toBe('ㅇㅖㅇㅡㅣ'); + expect(convertQwertyToAlphabet('RㅏㄱEㅜrl')).toBe('ㄲㅏㄱㄸㅜㄱㅣ'); + expect(convertQwertyToAlphabet('ㅇPdml')).toBe('ㅇㅖㅇㅡㅣ'); }); it('빈 문자열은 빈 문자열을 반환한다.', () => { - expect(convertQwertyToHangulAlphabet('')).toBe(''); + expect(convertQwertyToAlphabet('')).toBe(''); }); }); diff --git a/src/convertQwertyToHangulAlphabet.ts b/src/convertQwertyToAlphabet.ts similarity index 77% rename from src/convertQwertyToHangulAlphabet.ts rename to src/convertQwertyToAlphabet.ts index bcc4aa81..b4c1ae3f 100644 --- a/src/convertQwertyToHangulAlphabet.ts +++ b/src/convertQwertyToAlphabet.ts @@ -1,15 +1,15 @@ -import { assembleHangul } from './assemble'; +import { hasProperty } from './_internal'; +import { assemble } from './assemble'; import { QWERTY_KEYBOARD_MAP } from './constants'; -import { hasProperty } from './utils'; /** - * @name convertQwertyToHangulAlphabet + * @name convertQwertyToAlphabet * @description * 영어 알파벳을 qwerty 자판과 매칭되는 한글 음소로 변환합니다. * @param word 한글 음소로 변환하고자 하는 영문 * @returns 영어 알파벳이 포함되지 않은 한글 음소, 음절, 기타 문자로 이루어진 문자열 */ -export function convertQwertyToHangulAlphabet(word: string): string { +export function convertQwertyToAlphabet(word: string): string { return word .split('') .map(inputText => (hasProperty(QWERTY_KEYBOARD_MAP, inputText) ? QWERTY_KEYBOARD_MAP[inputText] : inputText)) @@ -27,5 +27,5 @@ export function convertQwertyToHangul(word: string): string { if (!word) { return ''; } - return assembleHangul([...convertQwertyToHangulAlphabet(word)]); + return assemble([...convertQwertyToAlphabet(word)]); } diff --git a/src/disassemble.spec.ts b/src/disassemble.spec.ts index d4d59c60..57e7ff20 100644 --- a/src/disassemble.spec.ts +++ b/src/disassemble.spec.ts @@ -1,12 +1,12 @@ -import { disassembleHangul, disassembleHangulToGroups } from './disassemble'; +import { disassemble, disassembleToGroups } from './disassemble'; -describe('disassembleHangulToGroups', () => { +describe('disassembleToGroups', () => { it('값', () => { - expect(disassembleHangulToGroups('값')).toEqual([['ㄱ', 'ㅏ', 'ㅂ', 'ㅅ']]); + expect(disassembleToGroups('값')).toEqual([['ㄱ', 'ㅏ', 'ㅂ', 'ㅅ']]); }); it('값이 비싸다', () => { - expect(disassembleHangulToGroups('값이 비싸다')).toEqual([ + expect(disassembleToGroups('값이 비싸다')).toEqual([ ['ㄱ', 'ㅏ', 'ㅂ', 'ㅅ'], ['ㅇ', 'ㅣ'], [' '], @@ -17,36 +17,36 @@ describe('disassembleHangulToGroups', () => { }); it('사과 짱', () => { - expect(disassembleHangulToGroups('사과 짱')).toEqual([['ㅅ', 'ㅏ'], ['ㄱ', 'ㅗ', 'ㅏ'], [' '], ['ㅉ', 'ㅏ', 'ㅇ']]); + expect(disassembleToGroups('사과 짱')).toEqual([['ㅅ', 'ㅏ'], ['ㄱ', 'ㅗ', 'ㅏ'], [' '], ['ㅉ', 'ㅏ', 'ㅇ']]); }); it('ㄵ', () => { - expect(disassembleHangulToGroups('ㄵ')).toEqual([['ㄴ', 'ㅈ']]); + expect(disassembleToGroups('ㄵ')).toEqual([['ㄴ', 'ㅈ']]); }); it('ㅘ', () => { - expect(disassembleHangulToGroups('ㅘ')).toEqual([['ㅗ', 'ㅏ']]); + expect(disassembleToGroups('ㅘ')).toEqual([['ㅗ', 'ㅏ']]); }); }); -describe('disassembleHangul', () => { +describe('disassemble', () => { it('값', () => { - expect(disassembleHangul('값')).toEqual('ㄱㅏㅂㅅ'); + expect(disassemble('값')).toEqual('ㄱㅏㅂㅅ'); }); it('값이 비싸다', () => { - expect(disassembleHangul('값이 비싸다')).toEqual('ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ'); + expect(disassemble('값이 비싸다')).toEqual('ㄱㅏㅂㅅㅇㅣ ㅂㅣㅆㅏㄷㅏ'); }); it('사과 짱', () => { - expect(disassembleHangul('사과 짱')).toEqual('ㅅㅏㄱㅗㅏ ㅉㅏㅇ'); + expect(disassemble('사과 짱')).toEqual('ㅅㅏㄱㅗㅏ ㅉㅏㅇ'); }); it('ㄵ', () => { - expect(disassembleHangul('ㄵ')).toEqual('ㄴㅈ'); + expect(disassemble('ㄵ')).toEqual('ㄴㅈ'); }); it('ㅘ', () => { - expect(disassembleHangul('ㅘ')).toEqual('ㅗㅏ'); + expect(disassemble('ㅘ')).toEqual('ㅗㅏ'); }); }); diff --git a/src/disassemble.ts b/src/disassemble.ts index a38432ca..f16e0b42 100644 --- a/src/disassemble.ts +++ b/src/disassemble.ts @@ -1,8 +1,8 @@ +import { hasProperty } from './_internal'; import { DISASSEMBLED_CONSONANTS_BY_CONSONANT, DISASSEMBLED_VOWELS_BY_VOWEL } from './constants'; -import { disassembleCompleteHangulCharacter } from './disassembleCompleteHangulCharacter'; -import { hasProperty } from './utils'; +import { disassembleCompleteCharacter } from './disassembleCompleteCharacter'; -export function disassembleHangulToGroups(str: string) { +export function disassembleToGroups(str: string) { /* * FIXME(@raon0211): * Array#map을 사용하는 경우 Safari에서 'Array size is not a small enough positive integer' 오류가 발생함. @@ -13,7 +13,7 @@ export function disassembleHangulToGroups(str: string) { const result: string[][] = []; for (const letter of str) { - const disassembledComplete = disassembleCompleteHangulCharacter(letter); + const disassembledComplete = disassembleCompleteCharacter(letter); if (disassembledComplete != null) { result.push([...disassembledComplete.first, ...disassembledComplete.middle, ...disassembledComplete.last]); @@ -40,6 +40,6 @@ export function disassembleHangulToGroups(str: string) { return result; } -export function disassembleHangul(str: string) { - return disassembleHangulToGroups(str).reduce((hanguls, disassembleds) => `${hanguls}${disassembleds.join('')}`, ''); +export function disassemble(str: string) { + return disassembleToGroups(str).reduce((hanguls, disassembleds) => `${hanguls}${disassembleds.join('')}`, ''); } diff --git a/src/disassembleCompleteCharacter.spec.ts b/src/disassembleCompleteCharacter.spec.ts new file mode 100644 index 00000000..716e3a25 --- /dev/null +++ b/src/disassembleCompleteCharacter.spec.ts @@ -0,0 +1,40 @@ +import { disassembleCompleteCharacter } from './disassembleCompleteCharacter'; + +describe('disassembleCompleteCharacter', () => { + it('값', () => { + expect(disassembleCompleteCharacter('값')).toEqual({ + first: 'ㄱ', + middle: 'ㅏ', + last: 'ㅂㅅ', + }); + }); + + it('리', () => { + expect(disassembleCompleteCharacter('리')).toEqual({ + first: 'ㄹ', + middle: 'ㅣ', + last: '', + }); + }); + + it('빚', () => { + expect(disassembleCompleteCharacter('빚')).toEqual({ + first: 'ㅂ', + middle: 'ㅣ', + last: 'ㅈ', + }); + }); + + it('박', () => { + expect(disassembleCompleteCharacter('박')).toEqual({ + first: 'ㅂ', + middle: 'ㅏ', + last: 'ㄱ', + }); + }); + + it('완전한 한글 문자열이 아니면 undefined를 반환해야 합니다.', () => { + expect(disassembleCompleteCharacter('ㄱ')).toBeUndefined; + expect(disassembleCompleteCharacter('ㅏ')).toBeUndefined; + }); +}); diff --git a/src/disassembleCompleteHangulCharacter.ts b/src/disassembleCompleteCharacter.ts similarity index 69% rename from src/disassembleCompleteHangulCharacter.ts rename to src/disassembleCompleteCharacter.ts index 252eee2d..43e54900 100644 --- a/src/disassembleCompleteHangulCharacter.ts +++ b/src/disassembleCompleteCharacter.ts @@ -8,29 +8,27 @@ import { NUMBER_OF_JUNGSEONG, } from './constants'; -interface ReturnTypeDisassembleCompleteHangulCharacter { +interface ReturnTypeDisassembleCompleteCharacter { first: (typeof HANGUL_CHARACTERS_BY_FIRST_INDEX)[number]; middle: (typeof HANGUL_CHARACTERS_BY_MIDDLE_INDEX)[number]; last: (typeof HANGUL_CHARACTERS_BY_LAST_INDEX)[number]; } /** - * @name disassembleCompleteHangulCharacter + * @name disassembleCompleteCharacter * @description * 완전한 한글 문자열을 초성, 중성, 종성으로 분리합니다. * * @param {string} letter 분리하고자 하는 완전한 한글 문자열 * * @example - * disassembleCompleteHangulCharacter('값') // { first: 'ㄱ', middle: 'ㅏ', last: 'ㅂㅅ' } - * disassembleCompleteHangulCharacter('리') // { first: 'ㄹ', middle: 'ㅣ', last: '' } - * disassembleCompleteHangulCharacter('빚') // { first: 'ㅂ', middle: 'ㅣ', last: 'ㅈ' } - * disassembleCompleteHangulCharacter('박') // { first: 'ㅂ', middle: 'ㅏ', last: 'ㄱ' } + * disassembleCompleteCharacter('값') // { first: 'ㄱ', middle: 'ㅏ', last: 'ㅂㅅ' } + * disassembleCompleteCharacter('리') // { first: 'ㄹ', middle: 'ㅣ', last: '' } + * disassembleCompleteCharacter('빚') // { first: 'ㅂ', middle: 'ㅣ', last: 'ㅈ' } + * disassembleCompleteCharacter('박') // { first: 'ㅂ', middle: 'ㅏ', last: 'ㄱ' } */ -export function disassembleCompleteHangulCharacter( - letter: string -): ReturnTypeDisassembleCompleteHangulCharacter | undefined { +export function disassembleCompleteCharacter(letter: string): ReturnTypeDisassembleCompleteCharacter | undefined { const charCode = letter.charCodeAt(0); const isCompleteHangul = COMPLETE_HANGUL_START_CHARCODE <= charCode && charCode <= COMPLETE_HANGUL_END_CHARCODE; diff --git a/src/disassembleCompleteHangulCharacter.spec.ts b/src/disassembleCompleteHangulCharacter.spec.ts deleted file mode 100644 index 97880110..00000000 --- a/src/disassembleCompleteHangulCharacter.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { disassembleCompleteHangulCharacter } from './disassembleCompleteHangulCharacter'; - -describe('disassembleCompleteHangulCharacter', () => { - it('값', () => { - expect(disassembleCompleteHangulCharacter('값')).toEqual({ - first: 'ㄱ', - middle: 'ㅏ', - last: 'ㅂㅅ', - }); - }); - - it('리', () => { - expect(disassembleCompleteHangulCharacter('리')).toEqual({ - first: 'ㄹ', - middle: 'ㅣ', - last: '', - }); - }); - - it('빚', () => { - expect(disassembleCompleteHangulCharacter('빚')).toEqual({ - first: 'ㅂ', - middle: 'ㅣ', - last: 'ㅈ', - }); - }); - - it('박', () => { - expect(disassembleCompleteHangulCharacter('박')).toEqual({ - first: 'ㅂ', - middle: 'ㅏ', - last: 'ㄱ', - }); - }); - - it('완전한 한글 문자열이 아니면 undefined를 반환해야 합니다.', () => { - expect(disassembleCompleteHangulCharacter('ㄱ')).toBeUndefined; - expect(disassembleCompleteHangulCharacter('ㅏ')).toBeUndefined; - }); -}); diff --git a/src/extractHangul.spec.ts b/src/extractHangul.spec.ts deleted file mode 100644 index b3fd84dd..00000000 --- a/src/extractHangul.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { extractHangul } from './extractHangul'; - -describe('extractHangul', () => { - it('숫자와 알파벳과 특수문자를 제외한 한글 반환', () => { - expect(extractHangul('안녕하세요1234abc!@#')).toBe('안녕하세요'); - }); - - it('한글이 없는 문자열', () => { - expect(extractHangul('1234abc')).toBe(''); - }); - - it('한글과 공백을 제외한 다른 문자는 제거', () => { - expect(extractHangul('한글과 영어가 섞인 문장입니다. Hello!')).toBe('한글과 영어가 섞인 문장입니다 '); - }); - - it('escape 문자열 유지', () => { - expect(extractHangul('한글과\n\t줄바꿈')).toBe('한글과\n\t줄바꿈'); - }); - - it('모음은 제거하지 않음', () => { - expect(extractHangul('ㅠㅠ')).toBe('ㅠㅠ'); - }); - - it('자음은 제거하지 않음', () => { - expect(extractHangul('ㄱㄴㄱㄴ')).toBe('ㄱㄴㄱㄴ'); - }); -}); diff --git a/src/extractHangul.ts b/src/extractHangul.ts deleted file mode 100644 index d023a674..00000000 --- a/src/extractHangul.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name extractHangul - * @description - * 문자열을 입력받고 한글만 추출해 반환합니다. - * - * @param {string} chars 모든 문자열 - * - * @example - * extractHangul('안녕하세요1234abc') // '안녕하세요' - * extractHangul('abcde') // '' - * extractHangul('안녕하세요ㄱㄴ') // '안녕하세요ㄱㄴ' - * extractHangul('안녕하세요 만나서 반갑습니다') // '안녕하세요 만나서 반갑습니다' - * extractHangul('가나다!-29~라마바.,,사') // '가나다라마바사' - */ - -export function extractHangul(str: string): string { - return str.replace(/[^ㄱ-ㅎㅏ-ㅣ가-힣\s]+/g, ''); -} diff --git a/src/getChoseong.spec.ts b/src/getChoseong.spec.ts new file mode 100644 index 00000000..ae1ddc4c --- /dev/null +++ b/src/getChoseong.spec.ts @@ -0,0 +1,20 @@ +import { getChoseong } from './getChoseong'; + +describe('getChoseong', () => { + it('"사과" 단어에서 초성 "ㅅㄱ"을 추출한다.', () => { + expect(getChoseong('사과')).toBe('ㅅㄱ'); + }); + it('"프론트엔드" 단어에서 초성 "ㅍㄹㅌㅇㄷ"을 추출한다.', () => { + expect(getChoseong('프론트엔드')).toBe('ㅍㄹㅌㅇㄷ'); + }); + it('"ㄴㅈ" 문자에서 초성 "ㄴㅈ"을 추출한다.', () => { + expect(getChoseong('ㄴㅈ')).toBe('ㄴㅈ'); + }); + it('"리액트" 단어에서 초성 "ㄹㅇㅌ"을 추출한다.', () => { + expect(getChoseong('리액트')).toBe('ㄹㅇㅌ'); + }); + + it('"띄어 쓰기" 문장에서 초성 "ㄸㅇ ㅆㄱ"을 추출한다.', () => { + expect(getChoseong('띄어 쓰기')).toBe('ㄸㅇ ㅆㄱ'); + }); +}); diff --git a/src/getChoseong.ts b/src/getChoseong.ts new file mode 100644 index 00000000..befd95f6 --- /dev/null +++ b/src/getChoseong.ts @@ -0,0 +1,31 @@ +import { HANGUL_CHARACTERS_BY_FIRST_INDEX, JASO_HANGUL_NFD } from './constants'; + +/** + * @name getChoseong + * @description + * 단어에서 초성을 추출합니다. (예: `사과` -> `'ㅅㄱ'`) + * ```typescript + * getChoseong( + * // 초성을 추출할 단어 + * word: string + * ): string + * ``` + * @example + * getChoseong('사과') // 'ㅅㄱ' + * getChoseong('띄어 쓰기') // 'ㄸㅇ ㅆㄱ' + */ +export function getChoseong(word: string) { + return word + .normalize('NFD') + .replace(EXTRACT_CHOSEONG_REGEX, '') // NFD ㄱ-ㅎ, NFC ㄱ-ㅎ 외 문자 삭제 + .replace(CHOOSE_NFD_CHOSEONG_REGEX, $0 => HANGUL_CHARACTERS_BY_FIRST_INDEX[$0.charCodeAt(0) - 0x1100]); // NFD to NFC +} + +const EXTRACT_CHOSEONG_REGEX = new RegExp( + `[^\\u${JASO_HANGUL_NFD.START_CHOSEONG.toString(16)}-\\u${JASO_HANGUL_NFD.END_CHOSEONG.toString(16)}ㄱ-ㅎ\\s]+`, + 'ug' +); +const CHOOSE_NFD_CHOSEONG_REGEX = new RegExp( + `[\\u${JASO_HANGUL_NFD.START_CHOSEONG.toString(16)}-\\u${JASO_HANGUL_NFD.END_CHOSEONG.toString(16)}]`, + 'g' +); diff --git a/src/hangulIncludes.spec.ts b/src/hangulIncludes.spec.ts deleted file mode 100644 index 451fb4ec..00000000 --- a/src/hangulIncludes.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { hangulIncludes } from './hangulIncludes'; - -describe('hangulIncludes', () => { - describe('한글이 포함되어있다고 판단되는 경우', () => { - it('사과', () => { - expect(hangulIncludes('사과', '')).toBe(true); - expect(hangulIncludes('사과', 'ㅅ')).toBe(true); - expect(hangulIncludes('사과', '삭')).toBe(true); - expect(hangulIncludes('사과', '사과')).toBe(true); - }); - - it('프론트엔드', () => { - expect(hangulIncludes('프론트엔드', '')).toBe(true); - expect(hangulIncludes('프론트엔드', '플')).toBe(true); - expect(hangulIncludes('프론트엔드', '틍')).toBe(true); - expect(hangulIncludes('프론트엔드', '플')).toBe(true); - expect(hangulIncludes('프론트엔드', '프로')).toBe(true); - }); - }); - - describe('한글이 포함되어있다고 판단되지 않는 경우', () => { - it('사과', () => { - expect(hangulIncludes('사과', '삽')).toBe(false); - }); - - it('프론트엔드', () => { - expect(hangulIncludes('프론트엔드', '픏')).toBe(false); - }); - }); -}); diff --git a/src/hangulIncludes.ts b/src/hangulIncludes.ts deleted file mode 100644 index f1376334..00000000 --- a/src/hangulIncludes.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { disassembleHangul } from './disassemble'; - -export function hangulIncludes(x: string, y: string) { - const disassembledX = disassembleHangul(x); - const disassembledY = disassembleHangul(y); - - return disassembledX.includes(disassembledY); -} diff --git a/src/hasBatchim.spec.ts b/src/hasBatchim.spec.ts new file mode 100644 index 00000000..ef9c58db --- /dev/null +++ b/src/hasBatchim.spec.ts @@ -0,0 +1,172 @@ +import { deserialize } from 'v8'; +import { hasBatchim } from './hasBatchim'; + +describe('hasBatchim', () => { + describe('받침이 있다고 판단되는 경우', () => { + it('"값" 문자에서 받침이 있으므로 true를 반환한다.', () => { + expect(hasBatchim('값')).toBe(true); + }); + it('"공" 문자에서 받침이 있으므로 true를 반환한다.', () => { + expect(hasBatchim('공')).toBe(true); + }); + it('"읊" 문자에서 받침이 있으므로 true를 반환한다.', () => { + expect(hasBatchim('읊')).toBe(true); + }); + }); + + describe('받침이 없다고 판단되는 경우', () => { + it('"토" 문자에서 받침이 없으므로 false를 반환한다.', () => { + expect(hasBatchim('토')).toBe(false); + }); + it('"서" 문자에서 받침이 없으므로 false를 반환한다.', () => { + expect(hasBatchim('서')).toBe(false); + }); + it('빈 문자열은 받침이 없으므로 false를 반환한다.', () => { + expect(hasBatchim('')).toBe(false); + }); + }); + + describe('완성된 한글이 아닌 경우', () => { + it('한글이 자음 또는 모음으로만 구성된 경우 false를 반환한다.', () => { + expect(hasBatchim('ㄱ')).toBe(false); + expect(hasBatchim('ㅏ')).toBe(false); + }); + + it('한글 외의 문자를 입력하면 false를 반환한다', () => { + expect(hasBatchim('cat')).toBe(false); + expect(hasBatchim('!')).toBe(false); + }); + }); +}); + +describe('홑받침', () => { + it('홑받침을 받으면 true를 반환한다.', () => { + expect( + hasBatchim('공', { + only: 'single', + }) + ).toBe(true); + + expect( + hasBatchim('핫', { + only: 'single', + }) + ).toBe(true); + + expect( + hasBatchim('양', { + only: 'single', + }) + ).toBe(true); + + expect( + hasBatchim('신', { + only: 'single', + }) + ).toBe(true); + + expect( + hasBatchim('확', { + only: 'single', + }) + ).toBe(true); + }); + + describe('홑받침이 아니라고 판단되는 경우', () => { + it('겹받침을 받으면 false를 반환한다.', () => { + expect( + hasBatchim('값', { + only: 'single', + }) + ).toBe(false); + + expect( + hasBatchim('읊', { + only: 'single', + }) + ).toBe(false); + + expect(hasBatchim('웱', { only: 'single' })).toBe(false); + }); + + it('받침이 없는 문자를 받으면 false를 반환한다.', () => { + expect(hasBatchim('토', { only: 'single' })).toBe(false); + expect(hasBatchim('서', { only: 'single' })).toBe(false); + expect(hasBatchim('와', { only: 'single' })).toBe(false); + }); + + it('한글 외의 문자를 입력하면 false를 반환한다.', () => { + expect(hasBatchim('cat', { only: 'single' })).toBe(false); + expect(hasBatchim('', { only: 'single' })).toBe(false); + expect(hasBatchim('?', { only: 'single' })).toBe(false); + }); + }); + + describe('겹받침', () => { + it('겹받침을 받으면 true를 반환한다.', () => { + expect( + hasBatchim('값', { + only: 'double', + }) + ).toBe(true); + + expect( + hasBatchim('읊', { + only: 'double', + }) + ).toBe(true); + + expect( + hasBatchim('웱', { + only: 'double', + }) + ).toBe(true); + }); + + describe('겹받침이 아니라고 판단되는 경우', () => { + it('홑받침을 받으면 false를 반환한다.', () => { + expect( + hasBatchim('공', { + only: 'double', + }) + ).toBe(false); + + expect( + hasBatchim('핫', { + only: 'double', + }) + ).toBe(false); + + expect( + hasBatchim('양', { + only: 'double', + }) + ).toBe(false); + + expect( + hasBatchim('신', { + only: 'double', + }) + ).toBe(false); + + expect( + hasBatchim('확', { + only: 'double', + }) + ).toBe(false); + }); + + it('받침이 없는 문자를 받으면 false를 반환한다.', () => { + expect(hasBatchim('토', { only: 'double' })).toBe(false); + expect(hasBatchim('서', { only: 'double' })).toBe(false); + expect(hasBatchim('와', { only: 'double' })).toBe(false); + }); + + it('한글 외의 문자를 입력하면 false를 반환한다.', () => { + expect(hasBatchim('cat', { only: 'double' })).toBe(false); + expect(hasBatchim('', { only: 'double' })).toBe(false); + expect(hasBatchim('?', { only: 'double' })).toBe(false); + }); + }); + }); +}); diff --git a/src/hasBatchim.ts b/src/hasBatchim.ts new file mode 100644 index 00000000..9fcfc2a3 --- /dev/null +++ b/src/hasBatchim.ts @@ -0,0 +1,61 @@ +import { + COMPLETE_HANGUL_END_CHARCODE, + COMPLETE_HANGUL_START_CHARCODE, + HANGUL_CHARACTERS_BY_LAST_INDEX, + NUMBER_OF_JONGSEONG, +} from './constants'; + +/** + * @name hasBatchim + * @description + * 한글 문자열의 마지막 글자가 받침이 있는지 확인합니다. + * ```typescript + * hasBatchim( + * // 글자에 받침이 있는지 확인하고 싶은 문자열 + * str: string, + * // 옵션 객체로 only 속성을 받을 수 있습니다. + * options?: { only?: "single" | "double" } + * ): boolean + * ``` + * @example + * hasBatchim('값') // true + * hasBatchim('토') // false + * hasBatchim('갑', { only: "single" }) // true + * hasBatchim('값', { only: "single" }) // false + * hasBatchim('값', { only: "double" }) // true + * hasBatchim('토', { only: "double" }) // false + */ +export function hasBatchim( + str: string, + options?: { + /** + * 체크할 받침의 종류 + * 사용하지 않으면 둘다 체크합니다. + */ + only?: 'single' | 'double'; + } +) { + const lastChar = str[str.length - 1]; + + if (lastChar == null) { + return false; + } + const charCode = lastChar.charCodeAt(0); + const isCompleteHangul = COMPLETE_HANGUL_START_CHARCODE <= charCode && charCode <= COMPLETE_HANGUL_END_CHARCODE; + + if (!isCompleteHangul) { + return false; + } + + const batchimCode = (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG; + + if (options?.only === 'single') { + return HANGUL_CHARACTERS_BY_LAST_INDEX[batchimCode].length === 1; + } + + if (options?.only === 'double') { + return HANGUL_CHARACTERS_BY_LAST_INDEX[batchimCode].length === 2; + } + + return batchimCode > 0; +} diff --git a/src/index.ts b/src/index.ts index 12bccb38..44ab09b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,25 +1,14 @@ -export { acronymizeHangul } from './acronymizeHangul'; -export { assembleHangul } from './assemble'; -export { choseongIncludes } from './choseongIncludes'; -export { chosungIncludes } from './chosungIncludes'; -export { combineHangulCharacter, combineVowels, curriedCombineHangulCharacter } from './combineHangulCharacter'; -export { convertQwertyToHangul, convertQwertyToHangulAlphabet } from './convertQwertyToHangulAlphabet'; -export { disassembleHangul, disassembleHangulToGroups } from './disassemble'; -export { disassembleCompleteHangulCharacter } from './disassembleCompleteHangulCharacter'; -export { extractHangul } from './extractHangul'; -export { hangulIncludes } from './hangulIncludes'; +export { assemble } from './assemble'; +export { combineCharacter, combineVowels } from './combineCharacter'; +export { convertQwertyToHangul, convertQwertyToAlphabet } from './convertQwertyToAlphabet'; +export { disassemble, disassembleToGroups } from './disassemble'; +export { disassembleCompleteCharacter } from './disassembleCompleteCharacter'; export { josa } from './josa'; -export { removeLastHangulCharacter } from './removeLastHangulCharacter'; +export { removeLastCharacter } from './removeLastCharacter'; export { romanize } from './romanize'; export { standardizePronunciation } from './standardizePronunciation'; export { susa } from './susa'; -export { - canBeChosung, - canBeJongsung, - canBeJungsung, - getChosung, - hasBatchim, - hasProperty, - hasSingleBatchim, - hasValueInReadOnlyStringList, -} from './utils'; +export { hasBatchim } from './hasBatchim'; +export { canBeChoseong, canBeJongseong, canBeJungseong } from './canBe'; +export { getChoseong } from './getChoseong'; +export { amountToHangul } from './amountToHangul'; diff --git a/src/josa.ts b/src/josa.ts index 6fc5c007..8f5de283 100644 --- a/src/josa.ts +++ b/src/josa.ts @@ -1,5 +1,5 @@ -import { disassembleCompleteHangulCharacter } from './disassembleCompleteHangulCharacter'; -import { hasBatchim } from './utils'; +import { disassembleCompleteCharacter } from './disassembleCompleteCharacter'; +import { hasBatchim } from './hasBatchim'; type JosaOption = | '이/가' @@ -37,7 +37,7 @@ function josaPicker(word: string, josa: JosaOption): string { const has받침 = hasBatchim(word); let index = has받침 ? 0 : 1; - const is종성ㄹ = disassembleCompleteHangulCharacter(word[word.length - 1])?.last === 'ㄹ'; + const is종성ㄹ = disassembleCompleteCharacter(word[word.length - 1])?.last === 'ㄹ'; const isCaseOf로 = has받침 && is종성ㄹ && 로_조사.includes(josa); diff --git a/src/removeLastHangulCharacter.spec.ts b/src/removeLastCharacter.spec.ts similarity index 52% rename from src/removeLastHangulCharacter.spec.ts rename to src/removeLastCharacter.spec.ts index 49e74fb9..ded3c260 100644 --- a/src/removeLastHangulCharacter.spec.ts +++ b/src/removeLastCharacter.spec.ts @@ -1,37 +1,37 @@ -import { removeLastHangulCharacter } from './removeLastHangulCharacter'; +import { removeLastCharacter } from './removeLastCharacter'; -describe('removeLastHangulCharacter', () => { +describe('removeLastCharacter', () => { it('마지막 문자가 겹받침인 경우 홑받침으로 바꾼다.', () => { - expect(removeLastHangulCharacter('안녕하세요 값')).toBe('안녕하세요 갑'); - expect(removeLastHangulCharacter('안녕하세요 값이')).toBe('안녕하세요 값ㅇ'); + expect(removeLastCharacter('안녕하세요 값')).toBe('안녕하세요 갑'); + expect(removeLastCharacter('안녕하세요 값이')).toBe('안녕하세요 값ㅇ'); }); it('마지막 문자가 초성과 중성의 조합으로 끝날 경우 초성만 남긴다.', () => { - expect(removeLastHangulCharacter('프론트엔드')).toBe('프론트엔ㄷ'); - expect(removeLastHangulCharacter('끓다')).toBe('끓ㄷ'); - expect(removeLastHangulCharacter('관사')).toBe('관ㅅ'); - expect(removeLastHangulCharacter('괴사')).toBe('괴ㅅ'); + expect(removeLastCharacter('프론트엔드')).toBe('프론트엔ㄷ'); + expect(removeLastCharacter('끓다')).toBe('끓ㄷ'); + expect(removeLastCharacter('관사')).toBe('관ㅅ'); + expect(removeLastCharacter('괴사')).toBe('괴ㅅ'); }); it('마지막 문자가 초성과 중성과 종성의 조합으로 끝날 경우 초성과 중성이 조합된 문자만 남긴다.', () => { - expect(removeLastHangulCharacter('일요일')).toBe('일요이'); - expect(removeLastHangulCharacter('완전')).toBe('완저'); - expect(removeLastHangulCharacter('왅전')).toBe('왅저'); - expect(removeLastHangulCharacter('깎')).toBe('까'); + expect(removeLastCharacter('일요일')).toBe('일요이'); + expect(removeLastCharacter('완전')).toBe('완저'); + expect(removeLastCharacter('왅전')).toBe('왅저'); + expect(removeLastCharacter('깎')).toBe('까'); }); it('마지막 문자가 초성과 중성의 조합으로 끝나며, 중성 입력 시 국제 표준 한글 레이아웃 기준 단일키로 처리되지 않는 이중모음 (ㅗ/ㅜ/ㅡ 계 이중모음) 인 경우 초성과 중성의 시작 모음만 남긴다.', () => { - expect(removeLastHangulCharacter('전화')).toBe('전호'); - expect(removeLastHangulCharacter('예의')).toBe('예으'); - expect(removeLastHangulCharacter('신세계')).toBe('신세ㄱ'); // 'ㅖ'의 경우 단일키 처리가 가능한 이중모음이므로 모음이 남지 않는다. + expect(removeLastCharacter('전화')).toBe('전호'); + expect(removeLastCharacter('예의')).toBe('예으'); + expect(removeLastCharacter('신세계')).toBe('신세ㄱ'); // 'ㅖ'의 경우 단일키 처리가 가능한 이중모음이므로 모음이 남지 않는다. }); it('마지막 문자가 초성과 중성과 종성의 조합으로 끝나며, 중성 입력 시 국제 표준 한글 레이아웃 기준 단일키로 처리되지 않는 이중모음 (ㅗ/ㅜ/ㅡ 계 이중모음) 인 경우 초성과 중성만 남긴다.', () => { - expect(removeLastHangulCharacter('수확')).toBe('수화'); + expect(removeLastCharacter('수확')).toBe('수화'); }); it('마지막 문자가 초성과 중성과 종성의 조합으로 끝나며, 종성이 겹자음인 경우 초성과 중성과 종성의 시작 자음만 남긴다.', () => { - expect(removeLastHangulCharacter('끓')).toBe('끌'); + expect(removeLastCharacter('끓')).toBe('끌'); }); it('마지막 문자가 초성과 중성과 종성의 조합으로 끝나며, 중성 입력 시 국제 표준 한글 레이아웃 기준 단일키로 처리되지 않는 이중모음 (ㅗ/ㅜ/ㅡ 계 이중모음)이고 종성이 겹자음인 경우 초성과 중성과 종성의 시작 자음만 남긴다.', () => { - expect(removeLastHangulCharacter('왅')).toBe('완'); + expect(removeLastCharacter('왅')).toBe('완'); }); it('빈 문자열일 경우 빈 문자열을 반환한다.', () => { - expect(removeLastHangulCharacter('')).toBe(''); + expect(removeLastCharacter('')).toBe(''); }); }); diff --git a/src/removeLastCharacter.ts b/src/removeLastCharacter.ts new file mode 100644 index 00000000..0aed34fe --- /dev/null +++ b/src/removeLastCharacter.ts @@ -0,0 +1,49 @@ +import { combineCharacter } from './combineCharacter'; +import { excludeLastElement } from './_internal'; +import { canBeJungseong } from './canBe'; +import { disassembleToGroups } from './disassemble'; + +/** + * @name removeLastCharacter + * @description + * 인자로 주어진 한글 문자열에서 가장 마지막 문자 하나를 제거하여 반환합니다. + * ```typescript + * removeLastCharacter( + * // 한글 문자열 + * words: string + * ): string + * ``` + * @example + * removeLastCharacter('안녕하세요 값') // 안녕하세요 갑 + * removeLastCharacter('프론트엔드') // 프론트엔ㄷ + * removeLastCharacter('일요일') // 일요이 + * removeLastCharacter('전화') // 전호 + * removeLastCharacter('신세계') // 신세ㄱ + */ +export function removeLastCharacter(words: string) { + const lastCharacter = words[words.length - 1]; + if (lastCharacter == null) { + return ''; + } + + const result = (() => { + const disassembleLastCharacter = disassembleToGroups(lastCharacter); + const [lastCharacterWithoutLastAlphabet] = excludeLastElement(disassembleLastCharacter[0]); + if (lastCharacterWithoutLastAlphabet.length <= 3) { + const [first, middle, last] = lastCharacterWithoutLastAlphabet; + if (middle != null) { + return canBeJungseong(last) + ? combineCharacter(first, `${middle}${last}`) + : combineCharacter(first, middle, last); + } + + return first; + } else { + const [first, firstJungsung, secondJungsung, firstJongsung] = lastCharacterWithoutLastAlphabet; + + return combineCharacter(first, `${firstJungsung}${secondJungsung}`, firstJongsung); + } + })(); + + return [words.substring(0, words.length - 1), result].join(''); +} diff --git a/src/removeLastHangulCharacter.ts b/src/removeLastHangulCharacter.ts deleted file mode 100644 index 5ac9c780..00000000 --- a/src/removeLastHangulCharacter.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { combineHangulCharacter } from './combineHangulCharacter'; -import { disassembleHangulToGroups } from './disassemble'; -import { excludeLastElement } from './_internal'; -import { canBeJungsung } from './utils'; - -/** - * @name removeLastHangulCharacter - * @description - * 인자로 주어진 한글 문자열에서 가장 마지막 문자 하나를 제거하여 반환합니다. - * ```typescript - * removeLastHangulCharacter( - * // 한글 문자열 - * words: string - * ): string - * ``` - * @example - * removeLastHangulCharacter('안녕하세요 값') // 안녕하세요 갑 - * removeLastHangulCharacter('프론트엔드') // 프론트엔ㄷ - * removeLastHangulCharacter('일요일') // 일요이 - * removeLastHangulCharacter('전화') // 전호 - * removeLastHangulCharacter('신세계') // 신세ㄱ - */ -export function removeLastHangulCharacter(words: string) { - const lastCharacter = words[words.length - 1]; - if (lastCharacter == null) { - return ''; - } - - const result = (() => { - const disassembleLastCharacter = disassembleHangulToGroups(lastCharacter); - const [lastCharacterWithoutLastAlphabet] = excludeLastElement(disassembleLastCharacter[0]); - if (lastCharacterWithoutLastAlphabet.length <= 3) { - const [first, middle, last] = lastCharacterWithoutLastAlphabet; - if (middle != null) { - return canBeJungsung(last) - ? combineHangulCharacter(first, `${middle}${last}`) - : combineHangulCharacter(first, middle, last); - } - - return first; - } else { - const [first, firstJungsung, secondJungsung, firstJongsung] = lastCharacterWithoutLastAlphabet; - - return combineHangulCharacter(first, `${firstJungsung}${secondJungsung}`, firstJongsung); - } - })(); - - return [words.substring(0, words.length - 1), result].join(''); -} diff --git a/src/romanize.ts b/src/romanize.ts index 14955228..f2d5f7a7 100644 --- a/src/romanize.ts +++ b/src/romanize.ts @@ -1,9 +1,9 @@ import { isHangulCharacter } from './_internal/hangul'; -import { assembleHangul } from './assemble'; +import { assemble } from './assemble'; +import { canBeChoseong } from './canBe'; import { 종성_알파벳_발음, 중성_알파벳_발음, 초성_알파벳_발음 } from './constants'; -import { disassembleCompleteHangulCharacter } from './disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from './disassembleCompleteCharacter'; import { standardizePronunciation } from './standardizePronunciation'; -import { canBeChoseong } from './utils'; /** * 주어진 한글 문자열을 로마자로 변환합니다. @@ -23,17 +23,17 @@ const romanizeSyllableHangul = (arrayHangul: string[], index: number): string => const syllable = arrayHangul[index]; if (isHangulCharacter(syllable)) { - const disassemble = disassembleCompleteHangulCharacter(syllable) as NonNullable< - ReturnType + const disassemble = disassembleCompleteCharacter(syllable) as NonNullable< + ReturnType >; let choseong: (typeof 초성_알파벳_발음)[keyof typeof 초성_알파벳_발음] | 'l' = 초성_알파벳_발음[disassemble.first]; - const jungseong = 중성_알파벳_발음[assembleHangul([disassemble.middle]) as keyof typeof 중성_알파벳_발음]; + const jungseong = 중성_알파벳_발음[assemble([disassemble.middle]) as keyof typeof 중성_알파벳_발음]; const jongseong = 종성_알파벳_발음[disassemble.last as keyof typeof 종성_알파벳_발음]; // 'ㄹ'은 모음 앞에서는 'r'로, 자음 앞이나 어말에서는 'l'로 적는다. 단, 'ㄹㄹ'은 'll'로 적는다. (ex.울릉, 대관령), if (disassemble.first === 'ㄹ' && index > 0 && isHangulCharacter(arrayHangul[index - 1])) { - const prevDisassemble = disassembleCompleteHangulCharacter(arrayHangul[index - 1]); + const prevDisassemble = disassembleCompleteCharacter(arrayHangul[index - 1]); if (prevDisassemble?.last === 'ㄹ') { choseong = 'l'; diff --git a/src/standardizePronunciation/index.ts b/src/standardizePronunciation/index.ts index 11cf110f..3c4e20cf 100644 --- a/src/standardizePronunciation/index.ts +++ b/src/standardizePronunciation/index.ts @@ -1,7 +1,7 @@ import { isNotUndefined, joinString } from '../_internal'; import { isHangulAlphabet, isHangulCharacter } from '../_internal/hangul'; -import { combineHangulCharacter } from '../combineHangulCharacter'; -import { disassembleCompleteHangulCharacter } from '../disassembleCompleteHangulCharacter'; +import { combineCharacter } from '../combineCharacter'; +import { disassembleCompleteCharacter } from '../disassembleCompleteCharacter'; import { transform12th, transform13And14th, @@ -88,7 +88,7 @@ function 음절분해(hangulPhrase: string): { return true; }) - .map(disassembleCompleteHangulCharacter) + .map(disassembleCompleteCharacter) .filter(isNotUndefined); return { notHangulPhrase, disassembleHangul }; @@ -146,7 +146,7 @@ function applyRules(params: ApplyParameters): { function assembleChangedHangul(disassembleHangul: Syllable[], notHangulPhrase: NotHangul[]): string { const changedSyllables = disassembleHangul .filter(isNotUndefined) - .map(syllable => combineHangulCharacter(syllable.first, syllable.middle, syllable.last)); + .map(syllable => combineCharacter(syllable.first, syllable.middle, syllable.last)); for (const { index, syllable } of notHangulPhrase) { changedSyllables.splice(index, 0, syllable); diff --git a/src/standardizePronunciation/rules/rules.types.ts b/src/standardizePronunciation/rules/rules.types.ts index 46eca0d6..53cf6fbb 100644 --- a/src/standardizePronunciation/rules/rules.types.ts +++ b/src/standardizePronunciation/rules/rules.types.ts @@ -1,8 +1,8 @@ -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; export type NonUndefined = T extends undefined ? never : T; export type Nullable = T | null | undefined; -export type Syllable = NonUndefined>; +export type Syllable = NonUndefined>; export type ReturnSyllables = { current: Syllable; next: Syllable; diff --git a/src/standardizePronunciation/rules/transform12th.spec.ts b/src/standardizePronunciation/rules/transform12th.spec.ts index be0c23d3..5a649def 100644 --- a/src/standardizePronunciation/rules/transform12th.spec.ts +++ b/src/standardizePronunciation/rules/transform12th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform12th } from './transform12th'; describe('transform12th', () => { it('"ㅎ, ㄶ, ㅀ" 뒤에 "ㄱ, ㄷ, ㅈ"이 결합되는 경우에는, 뒤 음절 첫소리와 합쳐서 "ㅋ, ㅌ, ㅊ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('놓')); - const next = defined(disassembleCompleteHangulCharacter('고')); + const current = defined(disassembleCompleteCharacter('놓')); + const next = defined(disassembleCompleteCharacter('고')); expect(transform12th(current, next)).toEqual({ current: { @@ -22,8 +22,8 @@ describe('transform12th', () => { }); it('받침 "ㄱ, ㄺ, ㄷ, ㅂ, ㄼ, ㅈ, ㄵ"이 뒤 음절 첫소리 "ㅎ"과 결합되는 경우에도, 역시 두 음을 합쳐서 "ㅋ, ㅌ, ㅍ, ㅊ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('각')); - const next = defined(disassembleCompleteHangulCharacter('하')); + const current = defined(disassembleCompleteCharacter('각')); + const next = defined(disassembleCompleteCharacter('하')); expect(transform12th(current, next)).toEqual({ current: { @@ -40,8 +40,8 @@ describe('transform12th', () => { }); it('"ㅎ, ㄶ, ㅀ" 뒤에 "ㅅ"이 결합되는 경우에는, "ㅅ"을 "ㅆ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('닿')); - const next = defined(disassembleCompleteHangulCharacter('소')); + const current = defined(disassembleCompleteCharacter('닿')); + const next = defined(disassembleCompleteCharacter('소')); expect(transform12th(current, next)).toEqual({ current: { @@ -58,8 +58,8 @@ describe('transform12th', () => { }); it('"ㅎ" 뒤에 "ㄴ"이 결합되는 경우에는 "ㄴ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('놓')); - const next = defined(disassembleCompleteHangulCharacter('는')); + const current = defined(disassembleCompleteCharacter('놓')); + const next = defined(disassembleCompleteCharacter('는')); expect(transform12th(current, next)).toEqual({ current: { @@ -76,8 +76,8 @@ describe('transform12th', () => { }); it('"ㄶ, ㅀ" 뒤에 "ㄴ"이 결합되는 경우에는, "ㅎ"을 발음하지 않는다', () => { - const current = defined(disassembleCompleteHangulCharacter('않')); - const next = defined(disassembleCompleteHangulCharacter('네')); + const current = defined(disassembleCompleteCharacter('않')); + const next = defined(disassembleCompleteCharacter('네')); expect(transform12th(current, next)).toEqual({ current: { @@ -94,8 +94,8 @@ describe('transform12th', () => { }); it('"ㅎ, ㄶ, ㅀ" 뒤에 모음으로 시작된 어미나 접미사가 결합되는 경우에는 "ㅎ"을 발음하지 않는다', () => { - const current = defined(disassembleCompleteHangulCharacter('낳')); - const next = defined(disassembleCompleteHangulCharacter('은')); + const current = defined(disassembleCompleteCharacter('낳')); + const next = defined(disassembleCompleteCharacter('은')); expect(transform12th(current, next)).toEqual({ current: { @@ -112,7 +112,7 @@ describe('transform12th', () => { }); it('"ㅎ, ㄶ, ㅀ" 뒤에 모음으로 시작된 어미나 접미사가 결합되는 경우에는 "ㅎ"을 발음하지 않는다', () => { - const current = defined(disassembleCompleteHangulCharacter('많')); + const current = defined(disassembleCompleteCharacter('많')); const next = null; expect(transform12th(current, next)).toEqual({ diff --git a/src/standardizePronunciation/rules/transform13And14th.spec.ts b/src/standardizePronunciation/rules/transform13And14th.spec.ts index 671b9687..f09e636a 100644 --- a/src/standardizePronunciation/rules/transform13And14th.spec.ts +++ b/src/standardizePronunciation/rules/transform13And14th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform13And14th } from './transform13And14th'; describe('transform13And14th', () => { it('13항을 적용합니다.', () => { - const current = defined(disassembleCompleteHangulCharacter('깎')); - const next = defined(disassembleCompleteHangulCharacter('아')); + const current = defined(disassembleCompleteCharacter('깎')); + const next = defined(disassembleCompleteCharacter('아')); expect(transform13And14th(current, next)).toEqual({ current: { @@ -22,8 +22,8 @@ describe('transform13And14th', () => { }); it('14항을 적용합니다.', () => { - const current = defined(disassembleCompleteHangulCharacter('닭')); - const next = defined(disassembleCompleteHangulCharacter('을')); + const current = defined(disassembleCompleteCharacter('닭')); + const next = defined(disassembleCompleteCharacter('을')); expect(transform13And14th(current, next)).toEqual({ current: { diff --git a/src/standardizePronunciation/rules/transform16th.spec.ts b/src/standardizePronunciation/rules/transform16th.spec.ts index e226bdd1..ee38a500 100644 --- a/src/standardizePronunciation/rules/transform16th.spec.ts +++ b/src/standardizePronunciation/rules/transform16th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform16th } from './transform16th'; describe('transform16th', () => { it('한글 자모의 이름은 그 받침소리를 연음하되, "ㄷ, ㅈ, ㅊ, ㅋ, ㅌ, ㅍ, ㅎ"의 경우에는 특별히 다음과 같이 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('귿')); - const next = defined(disassembleCompleteHangulCharacter('이')); + const current = defined(disassembleCompleteCharacter('귿')); + const next = defined(disassembleCompleteCharacter('이')); const phrase = '디귿이'; const index = 1; @@ -31,8 +31,8 @@ describe('transform16th', () => { }); it('자모의 이름이 "ㄱ, ㄴ, ㄹ, ㅁ, ㅂ, ㅅ, ㅇ"일 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('역')); - const next = defined(disassembleCompleteHangulCharacter('이')); + const current = defined(disassembleCompleteCharacter('역')); + const next = defined(disassembleCompleteCharacter('이')); const phrase = '기역이'; const index = 1; diff --git a/src/standardizePronunciation/rules/transform17th.spec.ts b/src/standardizePronunciation/rules/transform17th.spec.ts index aab32447..a371d420 100644 --- a/src/standardizePronunciation/rules/transform17th.spec.ts +++ b/src/standardizePronunciation/rules/transform17th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform17th } from './transform17th'; describe('transform17th', () => { it('받침 "ㄷ", "ㅌ(ㄾ)"이 조사나 접미사의 모음 "ㅣ"와 결합되는 경우에는, "ㅈ", "ㅊ"으로 바꾸어서 뒤 음절 첫소리로 옮겨 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('굳')); - const next = defined(disassembleCompleteHangulCharacter('이')); + const current = defined(disassembleCompleteCharacter('굳')); + const next = defined(disassembleCompleteCharacter('이')); expect(transform17th(current, next)).toEqual({ current: { @@ -22,8 +22,8 @@ describe('transform17th', () => { }); it('"ㄷ" 뒤에 접미사 "히"가 결합되어 "티"를 이루는 것은 "치"로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('굳')); - const next = defined(disassembleCompleteHangulCharacter('히')); + const current = defined(disassembleCompleteCharacter('굳')); + const next = defined(disassembleCompleteCharacter('히')); expect(transform17th(current, next)).toEqual({ current: { diff --git a/src/standardizePronunciation/rules/transform17th.ts b/src/standardizePronunciation/rules/transform17th.ts index bf3ab074..094a714c 100644 --- a/src/standardizePronunciation/rules/transform17th.ts +++ b/src/standardizePronunciation/rules/transform17th.ts @@ -1,4 +1,4 @@ -import { hasProperty } from '../../utils'; +import { hasProperty } from '../../_internal'; import { 음의_동화_받침 } from '../standardizePronunciation.constants'; import { ReturnSyllables, Syllable } from './rules.types'; diff --git a/src/standardizePronunciation/rules/transform18th.spec.ts b/src/standardizePronunciation/rules/transform18th.spec.ts index f7146469..c8f0da0d 100644 --- a/src/standardizePronunciation/rules/transform18th.spec.ts +++ b/src/standardizePronunciation/rules/transform18th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform18th } from './transform18th'; describe('transform18th', () => { it('받침 "ㄱ, ㄲ, ㅋ, ㄳ, ㄺ"일 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('먹')); - const next = defined(disassembleCompleteHangulCharacter('는')); + const current = defined(disassembleCompleteCharacter('먹')); + const next = defined(disassembleCompleteCharacter('는')); expect(transform18th(current, next)).toEqual({ current: { @@ -17,8 +17,8 @@ describe('transform18th', () => { }); it('받침 "ㄷ, ㅅ, ㅆ, ㅈ, ㅊ, ㅌ, ㅎ"일 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('닫')); - const next = defined(disassembleCompleteHangulCharacter('는')); + const current = defined(disassembleCompleteCharacter('닫')); + const next = defined(disassembleCompleteCharacter('는')); expect(transform18th(current, next)).toEqual({ current: { @@ -30,8 +30,8 @@ describe('transform18th', () => { }); it('받침 "ㅂ, ㅍ, ㄼ, ㄿ, ㅄ"일 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('잡')); - const next = defined(disassembleCompleteHangulCharacter('는')); + const current = defined(disassembleCompleteCharacter('잡')); + const next = defined(disassembleCompleteCharacter('는')); expect(transform18th(current, next)).toEqual({ current: { diff --git a/src/standardizePronunciation/rules/transform19th.spec.ts b/src/standardizePronunciation/rules/transform19th.spec.ts index b15c3434..f7858357 100644 --- a/src/standardizePronunciation/rules/transform19th.spec.ts +++ b/src/standardizePronunciation/rules/transform19th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform19th } from './transform19th'; describe('transform19th', () => { it('받침 "ㅁ, ㅇ" 뒤에 연결되는 "ㄹ"은 "ㄴ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('담')); - const next = defined(disassembleCompleteHangulCharacter('력')); + const current = defined(disassembleCompleteCharacter('담')); + const next = defined(disassembleCompleteCharacter('력')); expect(transform19th(current, next)).toEqual({ next: { @@ -17,8 +17,8 @@ describe('transform19th', () => { }); it('받침 "ㄱ, ㅂ" 뒤에 연결되는 "ㄹ"도 "ㄴ"으로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('막')); - const next = defined(disassembleCompleteHangulCharacter('론')); + const current = defined(disassembleCompleteCharacter('막')); + const next = defined(disassembleCompleteCharacter('론')); expect(transform19th(current, next)).toEqual({ next: { diff --git a/src/standardizePronunciation/rules/transform20th.spec.ts b/src/standardizePronunciation/rules/transform20th.spec.ts index c61ad2e0..9efd4335 100644 --- a/src/standardizePronunciation/rules/transform20th.spec.ts +++ b/src/standardizePronunciation/rules/transform20th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform20th } from './transform20th'; describe('transform20th', () => { it('"ㄴ"은 "ㄹ"의 앞이나 뒤에서 "ㄹ"로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('난')); - const next = defined(disassembleCompleteHangulCharacter('로')); + const current = defined(disassembleCompleteCharacter('난')); + const next = defined(disassembleCompleteCharacter('로')); expect(transform20th(current, next)).toEqual({ current: { @@ -22,8 +22,8 @@ describe('transform20th', () => { }); it('첫소리 "ㄴ"이 "ㅀ, ㄾ" 뒤에 연결되는 경우에도 "ㄹ"로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('닳')); - const next = defined(disassembleCompleteHangulCharacter('는')); + const current = defined(disassembleCompleteCharacter('닳')); + const next = defined(disassembleCompleteCharacter('는')); expect(transform20th(current, next)).toEqual({ current: { diff --git a/src/standardizePronunciation/rules/transform9And10And11th.spec.ts b/src/standardizePronunciation/rules/transform9And10And11th.spec.ts index b19a7d43..6f10d4de 100644 --- a/src/standardizePronunciation/rules/transform9And10And11th.spec.ts +++ b/src/standardizePronunciation/rules/transform9And10And11th.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transform9And10And11th } from './transform9And10And11th'; describe('transform9And10And11th', () => { it('9항 - 받침 "ㄲ, ㅋ" / "ㅅ, ㅆ, ㅈ, ㅊ, ㅌ" / "ㅍ"은 어말 또는 자음 앞에서 각각 대표음 "ㄱ, ㄷ, ㅂ"으로 발음한다.', () => { - const current = defined(disassembleCompleteHangulCharacter('닦')); - const next = disassembleCompleteHangulCharacter('다'); + const current = defined(disassembleCompleteCharacter('닦')); + const next = disassembleCompleteCharacter('다'); expect(transform9And10And11th(current, next)).toEqual({ current: { @@ -17,8 +17,8 @@ describe('transform9And10And11th', () => { }); it('10항 - 겹받침 "ㄳ" / "ㄵ" / "ㄼ, ㄽ, ㄾ" / "ㅄ"은 어말 또는 자음 앞에서 각각 "ㄱ, ㄴ, ㄹ, ㅂ"으로 발음한다.', () => { - const current = defined(disassembleCompleteHangulCharacter('앉')); - const next = disassembleCompleteHangulCharacter('다'); + const current = defined(disassembleCompleteCharacter('앉')); + const next = disassembleCompleteCharacter('다'); expect(transform9And10And11th(current, next)).toEqual({ current: { @@ -30,8 +30,8 @@ describe('transform9And10And11th', () => { }); it('11항 - 겹받침 "ㄺ" / "ㄻ" / "ㄿ"은 어말 또는 자음 앞에서 각각 "ㄱ, ㅁ, ㅂ"으로 발음한다.', () => { - const current = defined(disassembleCompleteHangulCharacter('흙')); - const next = disassembleCompleteHangulCharacter('과'); + const current = defined(disassembleCompleteCharacter('흙')); + const next = disassembleCompleteCharacter('과'); expect(transform9And10And11th(current, next)).toEqual({ current: { diff --git a/src/standardizePronunciation/rules/transform9And10And11th.ts b/src/standardizePronunciation/rules/transform9And10And11th.ts index 5886c250..65643fbe 100644 --- a/src/standardizePronunciation/rules/transform9And10And11th.ts +++ b/src/standardizePronunciation/rules/transform9And10And11th.ts @@ -1,4 +1,4 @@ -import { hasProperty } from '../../utils'; +import { hasProperty } from '../../_internal'; import { 받침_대표음_발음, 음가가_없는_자음 } from '../standardizePronunciation.constants'; import { Nullable, ReturnSyllables, Syllable } from './rules.types'; diff --git a/src/standardizePronunciation/rules/transformHardConversion.spec.ts b/src/standardizePronunciation/rules/transformHardConversion.spec.ts index 827f85a5..39323f48 100644 --- a/src/standardizePronunciation/rules/transformHardConversion.spec.ts +++ b/src/standardizePronunciation/rules/transformHardConversion.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transformHardConversion } from './transformHardConversion'; describe('transformHardConversion', () => { it('23항 - 받침 "ㄱ(ㄲ, ㅋ, ㄳ, ㄺ), ㄷ(ㅅ, ㅆ, ㅈ, ㅊ, ㅌ), ㅂ(ㅍ, ㄼ, ㄿ, ㅄ)" 뒤에 연결되는 "ㄱ, ㄷ, ㅂ, ㅅ, ㅈ"은 된소리로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('국')); - const next = defined(disassembleCompleteHangulCharacter('밥')); + const current = defined(disassembleCompleteCharacter('국')); + const next = defined(disassembleCompleteCharacter('밥')); expect(transformHardConversion(current, next)).toEqual({ next: { @@ -17,8 +17,8 @@ describe('transformHardConversion', () => { }); it('24항 - 어간 받침 "ㄴ(ㄵ), ㅁ(ㄻ)" 뒤에 결합되는 어미의 첫소리 "ㄱ, ㄷ, ㅅ, ㅈ"은 된소리로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('신')); - const next = defined(disassembleCompleteHangulCharacter('고')); + const current = defined(disassembleCompleteCharacter('신')); + const next = defined(disassembleCompleteCharacter('고')); expect(transformHardConversion(current, next)).toEqual({ next: { @@ -30,8 +30,8 @@ describe('transformHardConversion', () => { }); it('25항 - 어간 받침 "ㄼ, ㄾ" 뒤에 결합되는 어미의 첫소리 "ㄱ, ㄷ, ㅅ, ㅈ"은 된소리로 발음한다', () => { - const current = defined(disassembleCompleteHangulCharacter('넓')); - const next = defined(disassembleCompleteHangulCharacter('게')); + const current = defined(disassembleCompleteCharacter('넓')); + const next = defined(disassembleCompleteCharacter('게')); expect(transformHardConversion(current, next)).toEqual({ next: { diff --git a/src/standardizePronunciation/rules/transformHardConversion.ts b/src/standardizePronunciation/rules/transformHardConversion.ts index 3062ba46..53275f1d 100644 --- a/src/standardizePronunciation/rules/transformHardConversion.ts +++ b/src/standardizePronunciation/rules/transformHardConversion.ts @@ -1,5 +1,5 @@ import { arrayIncludes } from '../../_internal'; -import { hasProperty } from '../../utils'; +import { hasProperty } from '../../_internal'; import { 된소리, 된소리_받침, 어간_받침 } from '../standardizePronunciation.constants'; import { ReturnSyllables, Syllable } from './rules.types'; diff --git a/src/standardizePronunciation/rules/transformNLAssimilation.spec.ts b/src/standardizePronunciation/rules/transformNLAssimilation.spec.ts index 6ae0dfce..5c183a80 100644 --- a/src/standardizePronunciation/rules/transformNLAssimilation.spec.ts +++ b/src/standardizePronunciation/rules/transformNLAssimilation.spec.ts @@ -1,11 +1,11 @@ import { defined } from '../../_internal'; -import { disassembleCompleteHangulCharacter } from '../../disassembleCompleteHangulCharacter'; +import { disassembleCompleteCharacter } from '../../disassembleCompleteCharacter'; import { transformNLAssimilation } from './transformNLAssimilation'; describe('transformNLAssimilation', () => { it('받침이 "ㄱ, ㄴ, ㄷ, ㅁ, ㅂ, ㅇ"이고 다음 음절이 "야, 여, 요, 유, 이, 얘, 예"로 이어지는 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('맨')); - const next = defined(disassembleCompleteHangulCharacter('입')); + const current = defined(disassembleCompleteCharacter('맨')); + const next = defined(disassembleCompleteCharacter('입')); expect(transformNLAssimilation(current, next)).toEqual({ current: { @@ -22,8 +22,8 @@ describe('transformNLAssimilation', () => { }); it('받침이 "ㄹ"이고 다음 음절이 "야, 여, 요, 유, 이, 얘, 예"로 이어지는 경우', () => { - const current = defined(disassembleCompleteHangulCharacter('알')); - const next = defined(disassembleCompleteHangulCharacter('약')); + const current = defined(disassembleCompleteCharacter('알')); + const next = defined(disassembleCompleteCharacter('약')); expect(transformNLAssimilation(current, next)).toEqual({ current: { @@ -40,8 +40,8 @@ describe('transformNLAssimilation', () => { }); it('ㄴ/ㄹ이 되기 위한 조건이지만 현재 음절의 중성의 ∙(아래아)가 하나가 아닐 경우에는 덧나지 않고 연음규칙이 적용된다', () => { - const current = defined(disassembleCompleteHangulCharacter('양')); - const next = defined(disassembleCompleteHangulCharacter('이')); + const current = defined(disassembleCompleteCharacter('양')); + const next = defined(disassembleCompleteCharacter('이')); expect(transformNLAssimilation(current, next)).toEqual({ current: { diff --git a/src/susa.ts b/src/susa.ts index 6edb7a2a..342c2ad7 100644 --- a/src/susa.ts +++ b/src/susa.ts @@ -1,5 +1,5 @@ +import { hasProperty } from './_internal'; import { SUSA_MAP, SUSA_CLASSIFIER_MAP } from './constants'; -import { hasProperty } from './utils'; export function susa(num: number, classifier?: boolean): string { validateNumber(num); diff --git a/src/utils.spec.ts b/src/utils.spec.ts deleted file mode 100644 index 5edaa379..00000000 --- a/src/utils.spec.ts +++ /dev/null @@ -1,300 +0,0 @@ -import { arrayIncludes, isNotUndefined } from './_internal'; -import { - canBeChoseong, - canBeJongseong, - canBeJungseong, - getChoseong, - getFirstConsonants, - hasBatchim, - hasProperty, - hasSingleBatchim, - hasValueInReadOnlyStringList, -} from './utils'; - -describe('hasBatchim', () => { - describe('받침이 있다고 판단되는 경우', () => { - it('"값" 문자에서 받침이 있으므로 true를 반환한다.', () => { - expect(hasBatchim('값')).toBe(true); - }); - it('"공" 문자에서 받침이 있으므로 true를 반환한다.', () => { - expect(hasBatchim('공')).toBe(true); - }); - it('"읊" 문자에서 받침이 있으므로 true를 반환한다.', () => { - expect(hasBatchim('읊')).toBe(true); - }); - }); - - describe('받침이 없다고 판단되는 경우', () => { - it('"토" 문자에서 받침이 없으므로 false를 반환한다.', () => { - expect(hasBatchim('토')).toBe(false); - }); - it('"서" 문자에서 받침이 없으므로 false를 반환한다.', () => { - expect(hasBatchim('서')).toBe(false); - expect(hasBatchim('')).toBe(false); - }); - it('빈 문자열은 받침이 없으므로 false를 반환한다.', () => { - expect(hasBatchim('')).toBe(false); - }); - }); - - describe('완성된 한글이 아닌 경우', () => { - it('한글이 자음 또는 모음으로만 구성된 경우 false를 반환한다.', () => { - expect(hasBatchim('ㄱ')).toBe(false); - expect(hasBatchim('ㅏ')).toBe(false); - }); - - it('한글 외의 문자를 입력하면 false를 반환한다', () => { - expect(hasBatchim('cat')).toBe(false); - expect(hasBatchim('!')).toBe(false); - }); - }); -}); - -describe('hasSingleBatchim', () => { - it('홑받침을 받으면 true를 반환한다.', () => { - expect(hasSingleBatchim('공')).toBe(true); - expect(hasSingleBatchim('핫')).toBe(true); - expect(hasSingleBatchim('양')).toBe(true); - expect(hasSingleBatchim('신')).toBe(true); - expect(hasSingleBatchim('확')).toBe(true); - }); - - describe('홑받침이 아니라고 판단되는 경우', () => { - it('겹받침을 받으면 false를 반환한다.', () => { - expect(hasSingleBatchim('값')).toBe(false); - expect(hasSingleBatchim('읊')).toBe(false); - expect(hasSingleBatchim('웱')).toBe(false); - }); - - it('받침이 없는 문자를 받으면 false를 반환한다.', () => { - expect(hasSingleBatchim('토')).toBe(false); - expect(hasSingleBatchim('서')).toBe(false); - expect(hasSingleBatchim('와')).toBe(false); - }); - - it('한글 외의 문자를 입력하면 false를 반환한다.', () => { - expect(hasSingleBatchim('cat')).toBe(false); - expect(hasSingleBatchim('')).toBe(false); - expect(hasSingleBatchim('?')).toBe(false); - }); - - it('한글 외의 문자를 입력하면 false를 반환한다.', () => { - expect(hasSingleBatchim('cat')).toBe(false); - expect(hasSingleBatchim('')).toBe(false); - expect(hasSingleBatchim('?')).toBe(false); - }); - }); -}); - -describe('getChoseong', () => { - it('"사과" 단어에서 초성 "ㅅㄱ"을 추출한다.', () => { - expect(getChoseong('사과')).toBe('ㅅㄱ'); - }); - it('"프론트엔드" 단어에서 초성 "ㅍㄹㅌㅇㄷ"을 추출한다.', () => { - expect(getChoseong('프론트엔드')).toBe('ㅍㄹㅌㅇㄷ'); - }); - it('"ㄴㅈ" 문자에서 초성 "ㄴㅈ"을 추출한다.', () => { - expect(getChoseong('ㄴㅈ')).toBe('ㄴㅈ'); - }); - it('"리액트" 단어에서 초성 "ㄹㅇㅌ"을 추출한다.', () => { - expect(getChoseong('리액트')).toBe('ㄹㅇㅌ'); - }); - - it('"띄어 쓰기" 문장에서 초성 "ㄸㅇ ㅆㄱ"을 추출한다.', () => { - expect(getChoseong('띄어 쓰기')).toBe('ㄸㅇ ㅆㄱ'); - }); -}); - -describe('getFirstConsonants', () => { - it('"사과" 단어에서 초성 "ㅅㄱ"을 추출한다.', () => { - expect(getFirstConsonants('사과')).toBe('ㅅㄱ'); - }); - it('"프론트엔드" 단어에서 초성 "ㅍㄹㅌㅇㄷ"을 추출한다.', () => { - expect(getFirstConsonants('프론트엔드')).toBe('ㅍㄹㅌㅇㄷ'); - }); - it('"ㄴㅈ" 문자에서 초성 "ㄴㅈ"을 추출한다.', () => { - expect(getFirstConsonants('ㄴㅈ')).toBe('ㄴㅈ'); - }); - it('"리액트" 단어에서 초성 "ㄹㅇㅌ"을 추출한다.', () => { - expect(getFirstConsonants('리액트')).toBe('ㄹㅇㅌ'); - }); - - it('"띄어 쓰기" 문장에서 초성 "ㄸㅇ ㅆㄱ"을 추출된다.', () => { - expect(getFirstConsonants('띄어 쓰기')).toBe('ㄸㅇ ㅆㄱ'); - }); -}); - -describe('hasValueInReadOnlyStringList', () => { - const testReadonlyList = ['ㄱ', 'ㄴ', 'ㄷ'] as const; - - it('read-only 문자열 리스트에 요소가 존재한다면 true를 반환한다.', () => { - const testValue = 'ㄱ'; - - expect(hasValueInReadOnlyStringList(testReadonlyList, testValue)).toBeTruthy(); - }); - - it('read-only 문자열 리스트에 요소가 존재하지 않으면 false를 반환한다.', () => { - const testValue = 'ㄹ'; - - expect(hasValueInReadOnlyStringList(testReadonlyList, testValue)).toBeFalsy(); - }); - - it('read-only 문자열 리스트에 요소가 존재한다면 두 번째 인자의 타입을 좁힌다.', () => { - const testValue = 'ㄱ' as string; - - if (hasValueInReadOnlyStringList(testReadonlyList, testValue)) { - expectTypeOf(testValue).toEqualTypeOf<'ㄱ' | 'ㄴ' | 'ㄷ'>(); - } else { - expectTypeOf(testValue).toEqualTypeOf(); - } - }); -}); - -describe('hasProperty', () => { - const testObj = { ㄱ: 'ㄱ', ㄴ: 'ㄴ', ㄷ: 'ㄷ' } as const; - - it('객체에 속성이 존재하면 true를 반환한다.', () => { - const testKey = 'ㄱ'; - - expect(hasProperty(testObj, testKey)).toBeTruthy(); - }); - - it('객체에 속성이 존재하지 않으면 false를 반환한다.', () => { - const testKey = 'ㄹ'; - - expect(hasProperty(testObj, testKey)).toBeFalsy(); - }); - - it('객체에 속성이 존재한다면 두 번째 인자의 타입을 좁힌다.', () => { - const testKey = 'ㄱ' as string; - - if (hasProperty(testObj, testKey)) { - expectTypeOf(testKey).toEqualTypeOf<'ㄱ' | 'ㄴ' | 'ㄷ'>(); - } else { - expectTypeOf(testKey).toEqualTypeOf(); - } - }); -}); - -describe('canBeChoseong', () => { - describe('초성이 될 수 있다고 판단되는 경우', () => { - it('ㄱ', () => { - expect(canBeChoseong('ㄱ')).toBe(true); - }); - it('ㅃ', () => { - expect(canBeChoseong('ㅃ')).toBe(true); - }); - }); - - describe('초성이 될 수 없다고 판단되는 경우', () => { - it('ㅏ', () => { - expect(canBeChoseong('ㅏ')).toBe(false); - }); - it('ㅘ', () => { - expect(canBeChoseong('ㅘ')).toBe(false); - }); - it('ㄱㅅ', () => { - expect(canBeChoseong('ㄱㅅ')).toBe(false); - }); - it('가', () => { - expect(canBeChoseong('가')).toBe(false); - }); - }); -}); - -describe('canBeJungseong', () => { - describe('중성이 될 수 있다고 판단되는 경우', () => { - it('ㅗㅏ', () => { - expect(canBeJungseong('ㅗㅏ')).toBe(true); - }); - it('ㅏ', () => { - expect(canBeJungseong('ㅏ')).toBe(true); - }); - }); - - describe('중성이 될 수 없다고 판단되는 경우', () => { - it('ㄱ', () => { - expect(canBeJungseong('ㄱ')).toBe(false); - }); - it('ㄱㅅ', () => { - expect(canBeJungseong('ㄱㅅ')).toBe(false); - }); - it('가', () => { - expect(canBeJungseong('가')).toBe(false); - }); - }); -}); - -describe('canBeJongseong', () => { - describe('종성이 될 수 있다고 판단되는 경우', () => { - it('ㄱ', () => { - expect(canBeJongseong('ㄱ')).toBe(true); - }); - it('ㄱㅅ', () => { - expect(canBeJongseong('ㄱㅅ')).toBe(true); - }); - it('ㅂㅅ', () => { - expect(canBeJongseong('ㅂㅅ')).toBe(true); - }); - }); - - describe('종성이 될 수 없다고 판단되는 경우', () => { - it('ㅎㄹ', () => { - expect(canBeJongseong('ㅎㄹ')).toBe(false); - }); - it('ㅗㅏ', () => { - expect(canBeJongseong('ㅗㅏ')).toBe(false); - }); - it('ㅏ', () => { - expect(canBeJongseong('ㅏ')).toBe(false); - }); - it('가', () => { - expect(canBeJongseong('ㅏ')).toBe(false); - }); - }); -}); - -describe('isNotUndefined', () => { - it('정의된 값에 대해 true를 반환해야 한다', () => { - expect(isNotUndefined(5)).toBe(true); - expect(isNotUndefined('test')).toBe(true); - expect(isNotUndefined({})).toBe(true); - expect(isNotUndefined([])).toBe(true); - expect(isNotUndefined(null)).toBe(true); - }); - - it('undefined에 대해 false를 반환해야 한다', () => { - expect(isNotUndefined(undefined)).toBe(false); - }); -}); - -describe('arrayIncludes', () => { - it('값이 배열에 포함된 경우 true를 반환해야 한다', () => { - const array = ['a', 'b', 'c'] as const; - const value = 'a'; - const result = arrayIncludes(array, value); - expect(result).toBe(true); - }); - - it('값이 배열에 포함되지 않은 경우 false를 반환해야 한다', () => { - const array = ['a', 'b', 'c'] as const; - const value = 'd'; - const result = arrayIncludes(array, value); - expect(result).toBe(false); - }); - - it('undefined 값에 대해 false를 반환해야 합니다', () => { - const array = ['a', 'b', 'c'] as const; - const value = undefined; - const result = arrayIncludes(array, value); - expect(result).toBe(false); - }); - - it('검색을 시작할 인덱스를 기반으로 값을 반환합니다', () => { - const array: Array<'a' | 'b' | 'c'> = ['a', 'b', 'c']; - - const element = 'a'; - expect(arrayIncludes(array, element, 0)).toBe(true); - expect(arrayIncludes(array, element, 1)).toBe(false); - }); -}); diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index feef565b..00000000 --- a/src/utils.ts +++ /dev/null @@ -1,290 +0,0 @@ -import assert from './_internal'; -import { - COMPLETE_HANGUL_END_CHARCODE, - COMPLETE_HANGUL_START_CHARCODE, - HANGUL_CHARACTERS_BY_FIRST_INDEX, - HANGUL_CHARACTERS_BY_LAST_INDEX, - HANGUL_CHARACTERS_BY_MIDDLE_INDEX, - JASO_HANGUL_NFD, - NUMBER_OF_JONGSEONG, -} from './constants'; -import { disassembleHangulToGroups } from './disassemble'; - -const EXTRACT_CHOSEONG_REGEX = new RegExp( - `[^\\u${JASO_HANGUL_NFD.START_CHOSEONG.toString(16)}-\\u${JASO_HANGUL_NFD.END_CHOSEONG.toString(16)}ㄱ-ㅎ\\s]+`, - 'ug' -); -const CHOOSE_NFD_CHOSEONG_REGEX = new RegExp( - `[\\u${JASO_HANGUL_NFD.START_CHOSEONG.toString(16)}-\\u${JASO_HANGUL_NFD.END_CHOSEONG.toString(16)}]`, - 'g' -); - -/** - * @name hasBatchim - * @description - * 한글 문자열의 마지막 글자가 받침이 있는지 확인합니다. - * ```typescript - * hasBatchim( - * // 글자에 받침이 있는지 확인하고 싶은 문자열 - * str: string - * ): boolean - * ``` - * @example - * hasBatchim('값') // true - * hasBatchim('토') // false - */ -export function hasBatchim(str: string) { - const lastChar = str[str.length - 1]; - - if (lastChar == null) { - return false; - } - const charCode = lastChar.charCodeAt(0); - const isCompleteHangul = COMPLETE_HANGUL_START_CHARCODE <= charCode && charCode <= COMPLETE_HANGUL_END_CHARCODE; - - if (!isCompleteHangul) { - return false; - } - - return (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG > 0; -} - -/** - * @name hasSingleBatchim - * @description - * 한글 문자열의 마지막 글자가 홑받침이 있는지 확인합니다. - * ```typescript - * hasSingleBatchim( - * // 글자에 받침이 있는지 확인하고 싶은 문자열 - * str: string - * ): boolean - * ``` - * @example - * hasSingleBatchim('갑') // true - * hasSingleBatchim('값') // false - * hasSingleBatchim('토') // false - */ -export function hasSingleBatchim(str: string) { - const lastChar = str[str.length - 1]; - - if (lastChar == null) { - return false; - } - const charCode = lastChar.charCodeAt(0); - const isCompleteHangul = COMPLETE_HANGUL_START_CHARCODE <= charCode && charCode <= COMPLETE_HANGUL_END_CHARCODE; - - if (!isCompleteHangul) { - return false; - } - - const batchimCode = (charCode - COMPLETE_HANGUL_START_CHARCODE) % NUMBER_OF_JONGSEONG; - return HANGUL_CHARACTERS_BY_LAST_INDEX[batchimCode].length === 1; -} - -/** - * @name getChosung - * @deprecated getChoseong을 사용해 주세요. - * @description - * 단어에서 초성을 추출합니다. (예: `사과` -> `'ㅅㄱ'`) - * ```typescript - * getChoseong( - * // 초성을 추출할 단어 - * word: string - * ): string - * ``` - * @example - * getChoseong('사과') // 'ㅅㄱ' - * getChoseong('리액트') // 'ㄹㅇㅌ' - * getChoseong('띄어 쓰기') // 'ㄸㅇ ㅆㄱ' - */ -export function getChosung(word: string) { - return word - .normalize('NFD') - .replace(EXTRACT_CHOSEONG_REGEX, '') // NFD ㄱ-ㅎ, NFC ㄱ-ㅎ 외 문자 삭제 - .replace(CHOOSE_NFD_CHOSEONG_REGEX, $0 => HANGUL_CHARACTERS_BY_FIRST_INDEX[$0.charCodeAt(0) - 0x1100]); // NFD to NFC -} - -/** - * @name getChoseong - * @description - * 단어에서 초성을 추출합니다. (예: `사과` -> `'ㅅㄱ'`) - * ```typescript - * getChoseong( - * // 초성을 추출할 단어 - * word: string - * ): string - * ``` - * @example - * getChoseong('사과') // 'ㅅㄱ' - * getChoseong('리액트') // 'ㄹㅇㅌ' - * getChoseong('띄어 쓰기') // 'ㄸㅇ ㅆㄱ' - */ -export function getChoseong(word: string) { - return word - .normalize('NFD') - .replace(EXTRACT_CHOSEONG_REGEX, '') // NFD ㄱ-ㅎ, NFC ㄱ-ㅎ 외 문자 삭제 - .replace(CHOOSE_NFD_CHOSEONG_REGEX, $0 => HANGUL_CHARACTERS_BY_FIRST_INDEX[$0.charCodeAt(0) - 0x1100]); // NFD to NFC -} - -/** - * @name getFirstConsonants - * @deprecated getChoseong을 사용해 주세요. - * @description - * 단어에서 초성을 추출합니다. (예: `사과` -> `'ㅅㄱ'`) - * ```typescript - * getFirstConsonants( - * // 초성을 추출할 단어 - * word: string - * ): string - * ``` - * @example - * getFirstConsonants('사과') // 'ㅅㄱ' - * getFirstConsonants('리액트') // 'ㄹㅇㅌ' - * getFirstConsonants('띄어 쓰기') // 'ㄸㅇ ㅆㄱ' - */ -export function getFirstConsonants(word: string) { - return disassembleHangulToGroups(word).reduce((firstConsonants, [consonant]) => { - return `${firstConsonants}${consonant}`; - }, ''); -} - -/** - * @name canBeChosung - * @deprecated canBeChoseong을 사용해 주세요. - * @description - * 인자로 받은 문자가 초성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeChosung( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeChosung('ㄱ') // true - * canBeChosung('ㅃ') // true - * canBeChosung('ㄱㅅ') // false - * canBeChosung('ㅏ') // false - * canBeChosung('가') // false - */ -export function canBeChosung(character: string): character is (typeof HANGUL_CHARACTERS_BY_FIRST_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_FIRST_INDEX, character); -} - -/** - * @name canBeChoseong - * @description - * 인자로 받은 문자가 초성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeChoseong( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeChoseong('ㄱ') // true - * canBeChoseong('ㅃ') // true - * canBeChoseong('ㄱㅅ') // false - * canBeChoseong('ㅏ') // false - * canBeChoseong('가') // false - */ -export function canBeChoseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_FIRST_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_FIRST_INDEX, character); -} - -/** - * @name canBeJungsung - * @deprecated canBeJungseong을 사용해 주세요. - * @description - * 인자로 받은 문자가 중성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeJungsung( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeJungsung('ㅏ') // true - * canBeJungsung('ㅗㅏ') // true - * canBeJungsung('ㅏㅗ') // false - * canBeJungsung('ㄱ') // false - * canBeJungsung('ㄱㅅ') // false - * canBeJungsung('가') // false - */ -export function canBeJungsung(character: string): character is (typeof HANGUL_CHARACTERS_BY_MIDDLE_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_MIDDLE_INDEX, character); -} - -/** - * @name canBeJungseong - * @description - * 인자로 받은 문자가 중성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeJungseong( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeJungseong('ㅏ') // true - * canBeJungseong('ㅗㅏ') // true - * canBeJungseong('ㅏㅗ') // false - * canBeJungseong('ㄱ') // false - * canBeJungseong('ㄱㅅ') // false - * canBeJungseong('가') // false - */ -export function canBeJungseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_MIDDLE_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_MIDDLE_INDEX, character); -} - -/** - * @name canBeJongsung - * @deprecated canBeJongseong을 사용해 주세요. - * @description - * 인자로 받은 문자가 종성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeJongsung( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeJongsung('ㄱ') // true - * canBeJongsung('ㄱㅅ') // true - * canBeJongsung('ㅎㄹ') // false - * canBeJongsung('가') // false - * canBeJongsung('ㅏ') // false - * canBeJongsung('ㅗㅏ') // false - */ -export function canBeJongsung(character: string): character is (typeof HANGUL_CHARACTERS_BY_LAST_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_LAST_INDEX, character); -} - -/** - * @name canBeJongseong - * @description - * 인자로 받은 문자가 종성으로 위치할 수 있는 문자인지 검사합니다. - * ```typescript - * canBeJongseong( - * // 대상 문자 - * character: string - * ): boolean - * ``` - * @example - * canBeJongseong('ㄱ') // true - * canBeJongseong('ㄱㅅ') // true - * canBeJongseong('ㅎㄹ') // false - * canBeJongseong('가') // false - * canBeJongseong('ㅏ') // false - * canBeJongseong('ㅗㅏ') // false - */ -export function canBeJongseong(character: string): character is (typeof HANGUL_CHARACTERS_BY_LAST_INDEX)[number] { - return hasValueInReadOnlyStringList(HANGUL_CHARACTERS_BY_LAST_INDEX, character); -} - -export function hasValueInReadOnlyStringList(list: readonly T[], value: string): value is T { - return list.some(item => item === value); -} - -export function hasProperty(obj: T, key: K): key is K & keyof T { - return Object.prototype.hasOwnProperty.call(obj, key); -}