-
Notifications
You must be signed in to change notification settings - Fork 132
Open
Description
Description
josa 함수에서 누락된 조사 처리가 있습니다.
아래 목록은 참고를 위해 한국어 단어 데이터베이스 쿼리를 통해 구한 목록이며, 모든 한국어 조사를 포함하지는 않을 수도 있습니다.
목록:
- ⚪ 구어체적이어서 지원할 필요가 없는 것: ㄴ(은/는), ㄴ커녕(은커녕/는커녕), ㄹ(을/를)
- ✅ 이미 처리하고 있는 것: 이/가, 와/과, (이)나, 은/는, 은/는 + 커녕, (이)랑, (이)란, (으)로, (으)로부터, (으)로서, (으)로써, 을/를, 을/를 + 랑, 을/를 + 랑은, 아/야, 이에요/예요
- ⚪ 받침에 따라 바뀌지 않는 것: 같이, 곧**, 까지, 게, 게로, 게서, 깨나, 께, 께서, 께압서*, 께오서*, 께옵서, 끄정*, 다가, 대로, 더러, 도, 도고*, 두*, 들, 따라, 마냥*, 마다, 마따나, 마저, 마치*, 마콤*, 만, 만치, 만큼, 밖에, 버덤*, 보고, 보다, 부터, 뿐, 새려*, 새로에, 서, 서껀, 서부터, 서야, 설라믄*, 설랑은, 안테로*, 에, 에게, 에게다, 에게로, 에게서, 에는, 에다, 에다가, 에로, 에를, 에서, 에서부터, 에서야, 에야, 에의, 엔, 엘, 의, 조차, 처럼, 치고, 치고는, 치고서, 카냥*, 커녕, 토록, 하고, 하며, 한테, 한테로, 한테서, 할래*, 헌테*
- ❌ 처리하지 않고 있는 것: (이)고, (이)나마, (이)니, (이)다, 서술격 조사 (이)다, (이)든, (이)든가, (이)든지, (이)라, (이)라고, (이)라도, (이)라든가, (이)라든지, (이)라서, (이)라야, (이)라야만, (이)며, (이)면, (이)시여, (이)야, (이)야말로, (이)여, (이)요, 인들/ㄴ들, 인즉/ㄴ즉, 인즉슨/ㄴ즉슨, 일랑/ㄹ랑, 일랑은/ㄹ랑은
- ⚪ 규범 표기가 아닌 것: 사말로*, 이나따나*
- ⚪ 명사에 붙지 않는 것: -다 + 거나, -군/-구먼 등 + 그래, -하세/-ㅂ시다 + 그려, -다 + 마는, 손
- ❔ 규칙이 까다로운 것: 다가, 이랴
*: 규범 표기가 아님
**: 예스러운 표현
모든 조사를 꼭 지원할 필요는 없지만 몇몇 조사는 종종 쓰이는 경우가 있을 것 같아요. 가령 RPG 웹 게임에서 대사를 만든다든지요.
// 황혼검이야말로 대장장이 지크가 만든 최고 역작이지
// 핏빛 도끼야말로 대장장이 톰슨이 만든 최고 역작이지
show(`${josa(item, '이야말로/야말로')} 대장장이 ${josa(npcSmith.name, '이/가')} 만든 최고 역작이지.`)
const [strong1, strong2] = shuffled(strongEnemies)
// 오우거며 용아병이며 불꽃 도끼를 상대론 이길 수 없었지
show(`${josa(strong1.name, '이며/며')} ${josa(strong2.name, '이며/며')} ${josa(item, '을/를')} 상대론 이길 수 없었지.`)혹은 조건 나열에도 쓰일 법은 한데, 해당 케이스에는 아마 문장을 통으로 쓸 것 같아서 잘 쓰이진 않을 수도 있겠네요.
const reason: '이미 가입 중' | '만 19세 이하' | ... = ...;
`${josa(reason, '이라서/라서')} 가입할 수 없어요`Possible Solution
전제 조건
- 서술격 조사 이다의 경우 활용형이 너무 많아서 타입으로 잡는 데에 한계가 있고(심지어 코드베이스에 존재하는
'이에요/예요'처럼 축약형까지 고려하면 일반화가 꽤나 까다롭습니다)- 축약형은 고려하지 말아봅시다...
- 처리하지 않고 있는 대부분의 조사는
'이'가 생략되는 형태입니다.
해결책
-
위 조건을 고려할 때, 아래*와 같은 코드로 처리가 가능할 수 있습니다.
- 자동 완성이 필요하거나 예외 케이스(예요 등)가 필요하다면
JosaOption에 자주 쓰이는 조사를 미리 등록해두면 해결됩니다.
아래*
// Taken from type-fest. CC0-1.0. export type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends (<G>() => G extends B ? 1 : 2) ? true : false; type ISkip<T extends string> = T extends `이${infer L}/${infer R}` ? IsEqual<L, R> extends true ? T : never : never; type JosaOption = | '이/가' | '을/를' | '은/는' | '으로/로' | '와/과' | '아/야' | '이랑/랑' | '이에요/예요' | '으로서/로서' | '으로써/로써' | '으로부터/로부터'; declare function josa<T extends string>(word: string, josa: JosaOption | ISkip<T>): string; josa('돈', '이야말로/야말로') josa('돈', '이나/나') // @ts-expect-error josa('돈', '이야말로/야말') // @ts-expect-error josa('돈', '이나/이나나')
- 자동 완성이 필요하거나 예외 케이스(예요 등)가 필요하다면
-
특수한 조사 옵션
(이)를 만듭니다.- 이 경우
josa(str, '이나/나')를josa(str, '(이)') + '나'처럼 쓰게 됩니다. - 또는,
`(이)${string}`타입을 허용해서josa(str, '(이)나')처럼 처리할 수도 있습니다.- 런타임 코드에서는
startsWith('(이)')로 분기를 추가하게 되어 약간의 복잡도가 증가합니다. - 자동 완성이 필요하거나 예외 케이스(예요 등)가 필요하다면
JosaOption에 자주 쓰이는 조사를 미리 등록해두면 해결됩니다.
- 런타임 코드에서는
- 개인적으로 작성했던 스크립트에서 해당 방식을 채택했는데, 모든 조사를 나열하지 않고 쉽게 정의해 구현이 편리했었습니다만, 현재 es-hangul의 구현 방식 및 라이브러리 사용자 측 DX를 고려할 때 유리한 점이 없을 수도 있을 것 같습니다.
- 하위 호환성을 고려할 때 채택이 어려울 수도 있겠습니다.
- 이 경우
etc.
No response
changwoolab, bang9, okinawaa, BO-LIKE-CHICKEN and xnousnow
Metadata
Metadata
Assignees
Labels
No labels