Skip to content

Commit

Permalink
feat: 숫자를 순 우리말 서수사로 변환하는 함수 추가 (#307)
Browse files Browse the repository at this point in the history
* feat: 서수사 기능 구현

* feat: 서수사 테스트 추가

* refactor: 숫자 유효성 검증 로직 개선

Co-authored-by: 박찬혁 <[email protected]>

* docs: 서수사 함수 주석 보완

* docs: 서수사 함수 문서 추가

* fix: update seosusa function can handle more than 100 numbers

* update: seosusa test code

* update: seosusa documents

* Create modern-trains-change.md

---------

Co-authored-by: 박찬혁 <[email protected]>
  • Loading branch information
wet6123 and okinawaa authored Jan 6, 2025
1 parent 102f1e2 commit 5244525
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-trains-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"es-hangul": patch
---

feat: 숫자를 순 우리말 서수사로 변환하는 함수 추가
48 changes: 48 additions & 0 deletions docs/src/pages/docs/api/seosusa.en.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: seosusa
---

import { Sandpack } from '@/components/Sandpack';

# susa

Convert numbers to Korean ordinal words.
Integers from 1 to 99 are converted to native Korean ordinal words.
Integers greater than 100 are converted to Sino-Korean ordinal words.

```typescript
function seosusa(
// Number to convert
num: number
): string;
```

## Examples

```typescript
seosusa(1); // '첫째'
seosusa(2); // '둘째'
seosusa(3); // '셋째'
seosusa(10); // '열째'
seosusa(11); // '열한째'
seosusa(12); // '열두째'
seosusa(13); // '열셋째'
seosusa(20); // '스무째'
seosusa(21); // '스물한째'
seosusa(99); // '아흔아홉째'
seosusa(100); // '백째'
```

## Demo

<br />

<Sandpack>

```ts index.ts
import { seosusa } from 'es-hangul';

console.log(seosusa(1));
```

</Sandpack>
48 changes: 48 additions & 0 deletions docs/src/pages/docs/api/seosusa.ko.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: seosusa
---

import { Sandpack } from '@/components/Sandpack';

# seosusa

숫자를 한글 서수사로 변환합니다.
1부터 99까지의 정수는 순우리말 서수사 문자열로 변환합니다.
100 이상의 정수는 한자어 서수사 문자열로 변환합니다.

```typescript
function seosusa(
// 변환할 숫자
num: number
): string;
```

## Examples

```typescript
seosusa(1); // '첫째'
seosusa(2); // '둘째'
seosusa(3); // '셋째'
seosusa(10); // '열째'
seosusa(11); // '열한째'
seosusa(12); // '열두째'
seosusa(13); // '열셋째'
seosusa(20); // '스무째'
seosusa(21); // '스물한째'
seosusa(99); // '아흔아홉째'
seosusa(100); // '백째'
```

## 사용해보기

<br />

<Sandpack>

```ts index.ts
import { seosusa } from 'es-hangul';

console.log(seosusa(1));
```

</Sandpack>
27 changes: 27 additions & 0 deletions src/seosusa/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export const SEOSUSA_MAP = {
1: '한',
2: '두',
3: '셋',
4: '넷',
5: '다섯',
6: '여섯',
7: '일곱',
8: '여덟',
9: '아홉',
10: '열',
20: '스물',
30: '서른',
40: '마흔',
50: '쉰',
60: '예순',
70: '일흔',
80: '여든',
90: '아흔',
100: '백',
};

export const SEOSUSA_SPECIAL_CASE_MAP = {
1: '첫',
2: '둘',
20: '스무',
};
1 change: 1 addition & 0 deletions src/seosusa/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './seosusa';
44 changes: 44 additions & 0 deletions src/seosusa/seosusa.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { seosusa } from './seosusa';

describe('seosusa', () => {
const validNumbers = [
{ num: 1, word: '첫째' },
{ num: 2, word: '둘째' },
{ num: 3, word: '셋째' }, // '셋째'가 표준어이고 '세째'는 비표준어이다.(표준어 사정 원칙 제6항)
{ num: 4, word: '넷째' }, // '넷째'가 표준어이고 '네째'는 비표준어이다.(표준어 사정 원칙 제6항)
{ num: 5, word: '다섯째' },
{ num: 6, word: '여섯째' },
{ num: 7, word: '일곱째' },
{ num: 8, word: '여덟째' },
{ num: 9, word: '아홉째' },
{ num: 10, word: '열째' },
{ num: 11, word: '열한째' },
{ num: 12, word: '열두째' }, // '둘째'는 십 단위 이상의 서수사에 쓰일 때에 '두째'로 한다.(표준어 사정 원칙 제6항)
{ num: 13, word: '열셋째' },
{ num: 14, word: '열넷째' },
{ num: 15, word: '열다섯째' },
{ num: 20, word: '스무째' },
{ num: 21, word: '스물한째' },
{ num: 22, word: '스물두째' },
{ num: 30, word: '서른째' },
{ num: 40, word: '마흔째' },
{ num: 90, word: '아흔째' },
{ num: 99, word: '아흔아홉째' },
{ num: 100, word: '백째' },
{ num: 101, word: '백일째' },
];

const invalidNumbers = [0, -1, 1.1, -1.1, Infinity, -Infinity, NaN];

validNumbers.forEach(({ num, word }) => {
it(`${num} - 순 우리말 서수사로 변환한다.`, () => {
expect(seosusa(num)).toBe(word);
});
});

invalidNumbers.forEach(num => {
it(`${num} - 유효하지 않은 숫자에 대해 오류를 발생시켜야 한다.`, () => {
expect(() => seosusa(num)).toThrow('유효하지 않은 입력입니다. 1이상의 정수만 지원합니다.');
});
});
});
62 changes: 62 additions & 0 deletions src/seosusa/seosusa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { numberToHangul } from '@/numberToHangul';
import { hasProperty } from '../_internal';
import { SEOSUSA_MAP, SEOSUSA_SPECIAL_CASE_MAP } from './constants';

/**
* 숫자를 한글 서수사로 변환합니다.
*
* @remarks
* - **서수사**는 순서를 나타내는 단어입니다.
* - 1부터 99까지의 정수는 순우리말 서수사 문자열로 변환합니다.
* - 100 이상의 정수는 한자어 서수사 문자열로 변환합니다.
*
* @param num - 변환할 숫자
* @return 변환된 서수사 문자열
* @throws {Error} 지원하지 않는 숫자인 경우
*
* @example
* seosusa(1); // '첫째'
* seosusa(2); // '둘째'
* seosusa(3); // '셋째'
* seosusa(10); // '열째'
* seosusa(11); // '열한째'
* seosusa(12); // '열두째'
* seosusa(13); // '열셋째'
* seosusa(20); // '스무째'
* seosusa(21); // '스물한째'
* seosusa(30); // '서른째'
* seosusa(40); // '마흔째'
* seosusa(99); // '아흔아홉째'
* seosusa(100); // '백째'
*
* @see https://es-hangul.slash.page/docs/api/seosusa
*/
export function seosusa(num: number): string {
if (num === 0 || !Number.isInteger(num)) {
throw new Error('유효하지 않은 입력입니다. 1이상의 정수만 지원합니다.');
}

if (num >= 1 && num <= 99) {
return `${getOrdinalWord(num)}째`;
}

try {
return `${numberToHangul(num)}째`;
} catch (error) {
throw new Error('유효하지 않은 입력입니다. 1이상의 정수만 지원합니다.');
}
}

function getOrdinalWord(num: number): string {
if (hasProperty(SEOSUSA_SPECIAL_CASE_MAP, num)) {
return SEOSUSA_SPECIAL_CASE_MAP[num];
}

const tens = Math.floor(num / 10) * 10;
const ones = num % 10;

const tensWord = hasProperty(SEOSUSA_MAP, tens) ? SEOSUSA_MAP[tens] : '';
const onesWord = hasProperty(SEOSUSA_MAP, ones) ? SEOSUSA_MAP[ones] : '';

return `${tensWord}${onesWord}`;
}

0 comments on commit 5244525

Please sign in to comment.