Skip to content

Commit

Permalink
fix: 일관된 한글 표기법 적용 (#138)
Browse files Browse the repository at this point in the history
* fix: 일관된 한글 표기법 적용

* fix: 기존의 함수를 유지한 채, deprecated 되도록 수정

* fix: main 브랜치와 merge를 위한 수정

* fix: conflict 수정

* fix: 문서에는 chosung prefix를 사용하도록 수정

* fix: ChoseongIncludesDemo 함수명 수정

* chore: cspell.json 으로 설정을 변경합니다. (#172)

* fix: 일관된 한글 표기법 적용

* fix: 기존의 함수를 유지한 채, deprecated 되도록 수정

* docs: chosung~ 문서 작성

* fix: choseongIncludes의 인덱싱 처리

* Create fifty-wolves-melt.md

* fix: import CI 오류 해결

---------

Co-authored-by: Minsoo Kim <[email protected]>
Co-authored-by: 박찬혁 <[email protected]>
  • Loading branch information
3 people committed Jul 13, 2024
1 parent 135e419 commit 6160363
Show file tree
Hide file tree
Showing 22 changed files with 298 additions and 123 deletions.
5 changes: 5 additions & 0 deletions .changeset/fifty-wolves-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"es-hangul": patch
---

fix: chosung => choseong으로 변환하는 규칙을 적용합니다
4 changes: 2 additions & 2 deletions README-en_us.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ 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 { chosungIncludes } from 'es-hangul';
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput); // true
const result = choseongIncludes(searchWord, userInput); // true
```

```tsx
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
초성 검색, 조사 붙이기와 같은 한글 작업을 간단히 할 수 있습니다.

```tsx
import { chosungIncludes } from 'es-hangul';
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput); // true
const result = choseongIncludes(searchWord, userInput); // true
```

```tsx
Expand Down
27 changes: 27 additions & 0 deletions docs/src/pages/docs/api/choseongIncludes.en.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ChoseongIncludesDemo } from '@/components/demo/chosung-includes-demo';

# 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

<br />

<ChoseongIncludesDemo />
27 changes: 27 additions & 0 deletions docs/src/pages/docs/api/choseongIncludes.ko.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ChoseongIncludesDemo } from '@/components/demo/choseong-includes-demo';

# choseongIncludes

문자열의 초성 일치 검색을 수행합니다.

```typescript
function choseongIncludes(
// 초성 일치하는지 검사할 문자열 (e.g. '프론트엔드')
x: string,
// 초성 문자열 (e.g. 'ㅍㄹㅌㅇㄷ')
y: string
): boolean;
```

```typescript
choseongIncludes('프론트엔드', 'ㅍㄹㅌ'); // true
choseongIncludes('00프론트엔드', 'ㅍㄹㅌ'); // true
choseongIncludes('프론트엔드', 'ㅍㅌ'); // false
choseongIncludes('프론트엔드', '푸롴트'); // false
```

## 사용해보기

<br />

<ChoseongIncludesDemo />
2 changes: 1 addition & 1 deletion docs/src/pages/docs/api/chosungIncludes.en.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChosungIncludesDemo } from '@/components/demo/chosung-includes-demo';

# chosungIncludes
# chosungIncludes (deprecated, Please use choseongIncludes)

Performs a search for matches in the initial consonants of a string.

Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/docs/api/chosungIncludes.ko.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChosungIncludesDemo } from '@/components/demo/chosung-includes-demo';

# chosungIncludes
# chosungIncludes (deprecated, choseongIncludes를 사용해주세요)

문자열의 초성 일치 검색을 수행합니다.

Expand Down
10 changes: 5 additions & 5 deletions docs/src/pages/docs/introduction.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ 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/chosungIncludes) that can be conveniently used in various applications.
Our library provides a [modern API](./api/choseongIncludes) that can be conveniently used in various applications.

#### First Consonant Search ([chosungIncludes](./api/chosungIncludes))
#### First Consonant Search ([choseongIncludes](./api/choseongIncludes))

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 'ㄹㅁ'.

```tsx /chosungIncludes/
import { chosungIncludes } from 'es-hangul';
```tsx /choseongIncludes/
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput);
const result = choseongIncludes(searchWord, userInput);
console.log(result); // true
```

Expand Down
10 changes: 5 additions & 5 deletions docs/src/pages/docs/introduction.ko.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ ECMAScript Modules를 이용하여 사용하는 함수만 애플리케이션에

### 한글을 위한 모든 인터페이스를 제공하는 것을 목표합니다

다양한 애플리케이션에서 편리하게 사용할 수 있는 [현대적인 API](./api/chosungIncludes)를 제공합니다.
다양한 애플리케이션에서 편리하게 사용할 수 있는 [현대적인 API](./api/choseongIncludes)를 제공합니다.

#### 초성 검색 ([chosungIncludes](./api/chosungIncludes))
#### 초성 검색 ([choseongIncludes](./api/choseongIncludes))

초성이 특정 단어에 포함되어 있는지 검사합니다. 예를 들어, '라면'이라는 단어가 'ㄹㅁ'으로 시작하는 초성을 포함하는지 쉽게 알 수 있습니다.

```tsx /chosungIncludes/
import { chosungIncludes } from 'es-hangul';
```tsx /choseongIncludes/
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput);
const result = choseongIncludes(searchWord, userInput);
console.log(result); // true
```

Expand Down
7 changes: 4 additions & 3 deletions docs/src/pages/index.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@ import { Callout, useTheme, Steps } from 'nextra-theme-docs';
<h3 className="">A modern JavaScript Hangul library</h3>
</div>
<Callout className="w-full">
es-hangul is a small JavaScript library that helps you conveniently handle Hangul. It provides a convenient and clean API for actions such as searching for initial consonants and attaching particles.
es-hangul is a small JavaScript library that helps you conveniently handle Hangul. It provides a convenient and
clean API for actions such as searching for initial consonants and attaching particles.
</Callout>
</div>
</div>

```tsx
import { chosungIncludes } from 'es-hangul';
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput);
const result = choseongIncludes(searchWord, userInput);
console.log(result); // true
```

Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/index.ko.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ import { Callout, useTheme, Steps } from 'nextra-theme-docs';
</div>

```tsx
import { chosungIncludes } from 'es-hangul';
import { choseongIncludes } from 'es-hangul';

const searchWord = '라면';
const userInput = 'ㄹㅁ';

const result = chosungIncludes(searchWord, userInput);
const result = choseongIncludes(searchWord, userInput);
console.log(result); // true
```

Expand Down
12 changes: 8 additions & 4 deletions src/_internal/hangul.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,15 @@ describe('binaryAssembleHangulCharacters', () => {
});

it('다음 문자가 한글 문자 한 글자가 아니라면 Invalid next character 에러를 발생시킨다.', () => {
expect(() => binaryAssembleHangulCharacters('ㄱ', 'a')).toThrowError(
'Invalid next character: a. Next character must be one of the chosung, jungsung, or jongsung.'
assert.throws(
() => binaryAssembleHangulCharacters('ㄱ', 'a'),
Error,
'Invalid next character: a. Next character must be one of the choseong, jungseong, or jongseong.'
);
expect(() => binaryAssembleHangulCharacters('ㄱ', 'ㅡㅏ')).toThrowError(
'Invalid next character: ㅡㅏ. Next character must be one of the chosung, jungsung, or jongsung.'
assert.throws(
() => binaryAssembleHangulCharacters('ㄱ', 'ㅡㅏ'),
Error,
'Invalid next character: ㅡㅏ. Next character must be one of the choseong, jungseong, or jongseong.'
);
});
});
Expand Down
37 changes: 19 additions & 18 deletions src/_internal/hangul.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert, { excludeLastElement, isBlank, joinString } from '.';
import { combineHangulCharacter, combineVowels, curriedCombineHangulCharacter } from '../combineHangulCharacter';
import { disassembleHangulToGroups } from '../disassemble';
import { removeLastHangulCharacter } from '../removeLastHangulCharacter';
import { canBeChosung, canBeJongsung, canBeJungsung, hasSingleBatchim } from '../utils';
import { canBeChoseong, canBeJongseong, canBeJungseong, hasSingleBatchim } from '../utils';

export function isHangulCharacter(character: string) {
return /^[가-힣]$/.test(character);
Expand Down Expand Up @@ -57,12 +57,12 @@ export function safeParseHangul(actual: unknown): SafeParseSuccess | SafeParseEr
* ```
*/
export function binaryAssembleHangulAlphabets(source: string, nextCharacter: string) {
if (canBeJungsung(`${source}${nextCharacter}`)) {
if (canBeJungseong(`${source}${nextCharacter}`)) {
return combineVowels(source, nextCharacter);
}

const isConsonantSource = canBeJungsung(source) === false;
if (isConsonantSource && canBeJungsung(nextCharacter)) {
const isConsonantSource = canBeJungseong(source) === false;
if (isConsonantSource && canBeJungseong(nextCharacter)) {
return combineHangulCharacter(source, nextCharacter);
}

Expand Down Expand Up @@ -106,7 +106,7 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st
);
assert(
isHangulAlphabet(nextCharacter),
`Invalid next character: ${nextCharacter}. Next character must be one of the chosung, jungsung, or jongsung.`
`Invalid next character: ${nextCharacter}. Next character must be one of the choseong, jungseong, or jongseong.`
);

const sourceJamos = disassembleHangulToGroups(source)[0];
Expand All @@ -120,35 +120,36 @@ export function binaryAssembleHangulCharacters(source: string, nextCharacter: st
const [restJamos, lastJamo] = excludeLastElement(sourceJamos);
const secondaryLastJamo = excludeLastElement(restJamos)[1];

const needLinking = canBeChosung(lastJamo) && canBeJungsung(nextCharacter);
const needLinking = canBeChoseong(lastJamo) && canBeJungseong(nextCharacter);
if (needLinking) {
return linkHangulCharacters(source, nextCharacter);
}

const fixConsonant = curriedCombineHangulCharacter;
const combineJungsung = fixConsonant(restJamos[0]);
const combineJungseong = fixConsonant(restJamos[0]);

if (canBeJungsung(`${lastJamo}${nextCharacter}`)) {
return combineJungsung(`${lastJamo}${nextCharacter}`)();
if (canBeJungseong(`${lastJamo}${nextCharacter}`)) {
return combineJungseong(`${lastJamo}${nextCharacter}`)();
}

if (canBeJungsung(`${secondaryLastJamo}${lastJamo}`) && canBeJongsung(nextCharacter)) {
return combineJungsung(`${secondaryLastJamo}${lastJamo}`)(nextCharacter);
if (canBeJungseong(`${secondaryLastJamo}${lastJamo}`) && canBeJongseong(nextCharacter)) {
return combineJungseong(`${secondaryLastJamo}${lastJamo}`)(nextCharacter);
}

if (canBeJungsung(lastJamo) && canBeJongsung(nextCharacter)) {
return combineJungsung(lastJamo)(nextCharacter);
if (canBeJungseong(lastJamo) && canBeJongseong(nextCharacter)) {
return combineJungseong(lastJamo)(nextCharacter);
}

const fixVowel = combineJungsung;
const combineJongsung = fixVowel(
canBeJungsung(`${restJamos[1]}${restJamos[2]}`) ? `${restJamos[1]}${restJamos[2]}` : restJamos[1]
const fixVowel = combineJungseong;

const combineJongseong = fixVowel(
canBeJungseong(`${restJamos[1]}${restJamos[2]}`) ? `${restJamos[1]}${restJamos[2]}` : restJamos[1]
);

const lastConsonant = lastJamo;

if (hasSingleBatchim(source) && canBeJongsung(`${lastConsonant}${nextCharacter}`)) {
return combineJongsung(`${lastConsonant}${nextCharacter}`);
if (hasSingleBatchim(source) && canBeJongseong(`${lastConsonant}${nextCharacter}`)) {
return combineJongseong(`${lastConsonant}${nextCharacter}`);
}

return joinString(source, nextCharacter);
Expand Down
18 changes: 9 additions & 9 deletions src/chosungIncludes.spec.ts → src/choseongIncludes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { chosungIncludes } from './chosungIncludes';
import { choseongIncludes } from './choseongIncludes';

describe('chosungIncludes', () => {
describe('choseongIncludes', () => {
describe('초성이 포함되어있다고 판단되는 경우', () => {
it('"ㅍㄹㅌ" 문자열로 "프론트엔드"를 검색하면 true를 반환한다.', () => {
expect(chosungIncludes('프론트엔드', 'ㅍㄹㅌ')).toBe(true);
expect(choseongIncludes('프론트엔드', 'ㅍㄹㅌ')).toBe(true);
});

it('"ㅍㄹㅌ" 문자열로 "00프론트엔드"를 검색하면 true를 반환한다.', () => {
expect(chosungIncludes('00프론트엔드', 'ㅍㄹㅌ')).toBe(true);
expect(choseongIncludes('00프론트엔드', 'ㅍㄹㅌ')).toBe(true);
});

it('"ㅍㄹㅌㅇㄷㄱㅂㅈ" 문자열로 "프론트엔드 개발자"를 검색하면 true를 반환한다.', () => {
expect(chosungIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷㄱㅂㅈ')).toBe(true);
expect(choseongIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷㄱㅂㅈ')).toBe(true);
});

it('"ㅍㄹㅌㅇㄷ ㄱㅂㅈ" 문자열로 "프론트엔드 개발자"를 검색하면 true를 반환한다.', () => {
expect(chosungIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷ ㄱㅂㅈ')).toBe(true);
expect(choseongIncludes('프론트엔드 개발자', 'ㅍㄹㅌㅇㄷ ㄱㅂㅈ')).toBe(true);
});
});

describe('초성이 포함되어있다고 판단되지 않는 경우', () => {
it('"ㅍㅌ" 문자열로 "프론트엔드"를 검색하면 false를 반환한다.', () => {
expect(chosungIncludes('프론트엔드', 'ㅍㅌ')).toBe(false);
expect(choseongIncludes('프론트엔드', 'ㅍㅌ')).toBe(false);
});

it('빈 문자열로 "프론트엔드 개발자"를 검색하면 false를 반환한다.', () => {
expect(chosungIncludes('프론트엔드 개발자', ' ')).toBe(false);
expect(choseongIncludes('프론트엔드 개발자', ' ')).toBe(false);
});

it('"푸롴트" 문자열로 "프론트엔드"를 검색하면 초성으로만 구성되어 있지 않아 false를 반환한다.', () => {
expect(chosungIncludes('프론트엔드', '푸롴트')).toBe(false);
expect(choseongIncludes('프론트엔드', '푸롴트')).toBe(false);
});
});
});
29 changes: 29 additions & 0 deletions src/choseongIncludes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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]);
});
}
Loading

0 comments on commit 6160363

Please sign in to comment.