형태소 분석 API
형태소 분석 API 개요
형태소 분석 API는 한국어에 가장 적합하게 만들었습니다. 응답 메시지는 크게 문장, 어절, 형태 단위로 구분되어 있습니다.
- 문장은 각 요청한 텍스트를 문장으로 분리하여 그 결과물을 만들어 냅니다.
- 어절은 요청한 문장이 띄어쓰기를 기본으로 하지만, 자동 띄어쓰기 값을 참으로 요청하면,
어절의 내용을 바꿔서 응답합니다.
아름다운강산으로 입력으로 넣으면아름다운과강산을 분할해줍니다. - 어절은 붙여쓰기를 사용해서 붙이기도 합니다. 자주 틀리는 경우는 보조용언을 사용하는 경우입니다.
떨여 졌는데의 경우,떨어졌는데로 붙여쓰기를 해줍니다. - 형태소는 국립국어원의 47개 형태소 체계에 맞춰서 정확하게 분할해 줍니다.
- 원문의 위치에 따른 정확한 위치를 표기해 줍니다. 각 문장, 어절과 형태소는 모두 원래의 위치에 맞게 출력해줍니다.
- 단, 예외적으로 붙여쓰기가 일어난 경우에 활용이 일어난 경우에는 제대로 표현할 방법이 없어서 약간 다르게 나옵니다.
굴러 먹어서의 경우,구르+어 먹+어서로 분할될 수 있는데, 붙여쓰기 자동으로 보정할 경우에굴러먹+어서로 되기 때문에 위치를 정확하게 만드는 것이 힘듭니다. 대신에modified값을 표기해서 원문의 일부를 수정해서 인식했다는 점을 표기합니다.
사용해보기
Authorize를 눌러 ApiKey를 등록후 Try it out을 통해 이용해주세요.
형태소 분석 요청
요청 메시지 정의
// 형태소 분석 요청 메시지
message AnalyzeSyntaxRequest {
// 입력 문서
Document document = 1;
// 오프셋을 계산하기 위한 인코딩 타입
EncodingType encoding_type = 2;
// auto split sentence true이면 자동으로 문장 분리를 시도한다.
// 없으면 \n 을 기준으로 문장을 자른다.
// 기본값은 false 이다.
bool auto_split_sentence = 3;
// 커스텀 사전 도메인 정보
// v4.0에서는 폐기될 예정입니다. 새로운 custom_dict_names를 사용해주세요.
// 새로운 custom_dict_names에 값이 들어있는 경우, 이 값은 무시됩니다.
string custom_domain = 4 [deprecated = true];
// 자동 띄어쓰기
bool auto_spacing = 5;
// 자동 붙여쓰기
bool auto_jointing = 6;
// 커스텀 사전 이름들
// CustomDictionaryService를 사용해서 만든 사전을 여러 개 지정한다.
// 하나 이상의 지정할 경우, 먼저 나오는 사전이 우선되어 사용된다.
repeated string custom_dict_names = 11;
}
message Document {
// 입력 전체의 내용
// 여러 문장이 입력되면 "\n"을 넣어준다.
string content = 2;
// 문서의 언어. 현재는 ko_KR 만 지원한다.
string language = 4;
}
enum EncodingType {
NONE = 0;
UTF8 = 1;
UTF16 = 2;
UTF32 = 3;
}
요청 메시지에 대한 설명
| 변수 | 서브 변수 | 설명 |
|---|---|---|
| document | content | 메시지는 여러 문장으로 된 텍스트를 넣습니다. 기본적으로 문장을 분할해줍니다. |
| language | ko_KR을 넣어줍니다. 일반적으로 이 규격은 언어와 그 언어가 쓰이는 나라 정보를 넣어주는 것으로 볼 수 있습니다. 나중에 바른이 북한에서 쓰이는 조선어도 처리할 수 있다고 한다면, ko_KP가 쓰일 수 있을 것입니다. |
|
| auto_split_sentence | 자동으로 문장의 경계를 구분하고 싶을 때에는 요청 메시지의 이 값을 참(true)으로 설정하세요. 이 값이 false이면, 줄바꿈 LF를 기준으로 문장을 분할합니다. 윈도우 또는 도스의 CRLF 방식은 선호하지 않습니다. |
|
| encoding_type | EncodingType은 분석할 때, 각 단어의 위치 정보를 계산하는 방법을 정합니다. "안녕하세요"를 "안녕", "하", "시", "어요"로 구분될 때, "하"의 시작 위치가 6이면 UTF-8 인코딩 방식이고, 2이면 UTF-16 인코딩이거나 UTF-32 인코딩이 됩니다. 기본적으로 파이썬과 같은 언어에서는 UTF32가 쓰입니다. 클라이언트 개발 언어별로 결정되어 있다고 보는 게 맞습니다. C++에서 std::wstring 를 쓰시면 UTF32를 쓰는 것이 맞고, 일반 std::string를 쓰시면 UTF8을 쓰시는 게 맞습니다. 통상적으로 Go언어, C++의 경우에는 UTF-8을 씁니다. 자바의 경우에는 UTF-16이 쓰입니다. |
|
| custom_domain | 등록한 사용자 사전의 이름을 기입합니다. |
|
| auto_spacing | 띄어쓰기 보정을 수행하도록 합니다. | |
| auto_jointing | 붙여쓰기 자동 보정을 수행하도록 합니다. | |
| custom_dict_names | CustoCustomDictionaryService를 사용해서 만든 사전을 여러 개 지정합니다. 하나 이상의 지정할 경우, 먼저 나오는 사전이 우선되어 사용된다. |
encoding_type
인코딩 타입 API 규격은 구글의 자연어 처리 API를 참고하여서 가져왔습니다.
클라이언트에서 호출 후에 형태의 원본을 표시해줘야 하는 경우에 위치 값은 매우 중요합니다.
API의 규격에 따라서 위치가 바뀔 수 있으므로 서버에서 일관되게 변경해주는 것이 좋습니다.
UTF16의 경우에는 65535개의 유니코드만 지원하기 때문에 최근에 나온 이모티콘, 한자 등은 이 범위를 넘어서기도 합니다.
따라서 UTF16과 UTF32이 늘 같은 결과를 가져오지는 않습니다.
custom_domain_names
형태소 분석 수행할 때, 사용자 사전을 하나 이상 정의할 수 있습니다. 업무에 따라서 다양한 사전을 정의했다가, 이들을 지정할 수 있습니다. 사용자 사전에 등록된 단어는 다르게 분석할 수 있습니다.
여러 개 사전을 지정하여 호출하는 경우, 순서는 먼저 지정한 사전부터 처리하도록 구성되어 있습니다.
형태소 분석 요청(문장 분할 하지 않음)
만약 문장 분할 기능을 원하지 않을 경우 AnalyzeSyntaxList API를 사용하여 입력된 문장을 그대로 반환할 수 있습니다.
긴 문장을 여러 번 요청할 때, 입력된 문장의 순서, 텍스트 내의 어절의 위치 등을 추적한다면 유용하게 쓰일 수 있습니다.
- 앞선 형태소 분석 요청 API와 동일하지만 문자열이 아닌 문자열의 배열로 요청한다는 점에서 차이가 있습니다.
- auto_split_sentence 변수가 제외되었습니다.
요청 메시지 정의
// 형태소 분석 요청 메시지
message AnalyzeSyntaxListRequest {
// 입력 문장의 배열
repeated string sentences = 1;
// 입력 문장의 언어
string language = 2;
// 오프셋을 계산하기 위한 인코딩 타입
EncodingType encoding_type = 3;
// 커스텀 사전 도메인 정보
// v4.0에서는 폐기될 예정입니다. 새로운 custom_dict_names를 사용해주세요.
// 새로운 custom_dict_names에 값이 들어있는 경우, 이 값은 무시됩니다.
string custom_domain = 4 [deprecated = true];
// 자동 띄어쓰기
bool auto_spacing = 5;
// 자동 붙여쓰기
bool auto_jointing = 6;
// 커스텀 사전 이름들
// CustomDictionaryService를 사용해서 만든 사전을 여러 개 지정한다.
// 하나 이상의 지정할 경우, 먼저 나오는 사전이 우선되어 사용된다.
repeated string custom_dict_names = 11;
}
요청 메시지에 대한 설명
| 변수 | 설명 |
|---|---|
| sentences | 배열로 이루어진 텍스트를 넣습니다. |
| language | ko_KR을 넣어줍니다. 일반적으로 이 규격은 언어와 그 언어가 쓰이는 나라 정보를 넣어주는 것으로 볼 수 있습니다. 나중에 바른이 북한에서 쓰이는 조선어도 처리할 수 있다고 한다면, ko_KP가 쓰일 수 있을 것입니다. |
| encoding_type | EncodingType은 분석할 때, 각 단어의 위치 정보를 계산하는 방법을 정합니다. "안녕하세요"를 "안녕", "하", "시", "어요"로 구분될 때, "하"의 시작 위치가 6이면 UTF-8 인코딩 방식이고, 2이면 UTF-16 인코딩이거나 UTF-32 인코딩이 됩니다. 기본적으로 파이썬과 같은 언어에서는 UTF32가 쓰입니다. 클라이언트 개발 언어별로 결정되어 있다고 보는 게 맞습니다. C++에서 std::wstring 를 쓰시면 UTF32를 쓰는 것이 맞고, 일반 std::string를 쓰시면 UTF8을 쓰시는 게 맞습니다. 통상적으로 Go언어, C++의 경우에는 UTF-8을 씁니다. 자바의 경우에는 UTF-16이 쓰입니다. |
| custom_domain | 등록한 사용자 사전의 이름을 기입합니다. |
| auto_spacing | 띄어쓰기 보정을 수행하도록 합니다. |
| auto_jointing | 붙여쓰기 자동 보정을 수행하도록 합니다. |
| custom_dict_names | CustoCustomDictionaryService를 사용해서 만든 사전을 여러 개 지정합니다. 하나 이상의 지정할 경우, 먼저 나오는 사전이 우선되어 사용된다. |
형태소 분석 응답
응답 메시지 정의
message AnalyzeSyntaxResponse {
repeated Sentence sentences = 1;
string language = 3;
// 어절의 개수
int32 tokens_count = 100;
}
// 입력 문서에 분석된 문장
message Sentence {
// The sentence text.
TextSpan text = 1;
// 어절단위로 쪼개는 것은
repeated Token tokens = 2;
// 띄어쓰기 등의 오류를 수정한 결과물
string refined = 3;
}
message Token {
TextSpan text = 1;
repeated Morpheme morphemes = 2;
string lemma = 4;
string tagged = 5;
string modified = 11;
}
// 형태소
message Morpheme {
// The sentence text.
TextSpan text = 1;
// 형태소 태그
Tag tag = 2;
// 형태소 분석 결과 확률
float probability = 3;
// 유의어 번호
// int32 disambiguation = 4;
// 사전에 없는 단어 표시
OutOfVocab out_of_vocab = 5;
// 사전에 없는 단어 정보 처리 결과
enum OutOfVocab {
IN_WORD_EMBEDDING = 0; // 워드 임베딩에 포함된 내용
OUT_OF_VOCAB = 1; // 자동 추측, 미등록 단어
IN_CUSTOM_DICT = 2; // 사용자 제공 사전에 있는 내용
IN_BUILTIN_DICT = 3; // 기본 사전에 포함된 내용
}
// 사용된 사용자 사전의 이름
optional string custom_dict_name = 6;
// 내부적으로 pred 된 형태소는 0~46까지 반환하지만,
// 1~47까지 숫자로 쓰고, UNK은 0으로 바꾼다.
enum Tag {
//// 0 1 EC
//// 1 2 EF
//// 2 3 EP
//// 3 4 ETM
//// 4 5 ETN
//// 5 6 IC
//// 6 7 JC
//// 7 8 JKB
//// 8 9 JKC
//// 9 10 JKG
//// 10 11 JKO
//// 11 12 JKQ
//// 12 13 JKS
//// 13 14 JKV
//// 14 15 JX
//// 15 16 MAG
//// 16 17 MAJ
//// 17 18 MMA
//// 18 19 MMD
//// 19 20 MMN
//// 20 21 NA
//// 21 22 NF
//// 22 23 NNB
//// 23 24 NNG
//// 24 25 NNP
//// 25 26 NP
//// 26 27 NR
//// 27 28 NV
//// 28 29 SE
//// 29 30 SF
//// 30 31 SH
//// 31 32 SL
//// 32 33 SN
//// 33 34 SO
//// 34 35 SP
//// 35 36 SS
//// 36 37 SW
//// 37 38 VA
//// 38 39 VCN
//// 39 40 VCP
//// 40 41 VV
//// 41 42 VX
//// 42 43 XPN
//// 43 44 XR
//// 44 45 XSA
//// 45 46 XSN
//// 46 47 XSV
UNK = 0;
NNG = 24; // 일반 명사
NNP = 25; // 고유 명사
NNB = 23; // 의존 명사
NP = 26; // 대명사
NR = 27; // 수사
NF = 22; // 명사 추정 범주
NA = 21; // 분석불능범주
NV = 28; // 용언 추정 범주
VV = 41; // 동사
VA = 38; // 형용사
VX = 42; // 보조 용언
VCP = 40; // 긍정 지정사
VCN = 39; // 부정 지정사
MMA = 18; // 성상 관형사
MMD = 19; // 지시 관형사
MMN = 20; // 수 관형사
MAG = 16; // 일반 부사
MAJ = 17; // 접속 부사
IC = 6; // 감탄사
JKS = 13; // 주격 조사
JKC = 9; // 보격 조사
JKG = 10; // 관형격 조사
JKO = 11; // 목적격 조사
JKB = 8; // 부사격 조사
JKV = 14; // 호격 조사
JKQ = 12; // 인용격 조사
JX = 15; // 보조사
JC = 7; // 접속 조사
EP = 3; // 선어말 어미
EF = 2; // 종결 어미
EC = 1; // 연결 어미
ETN = 5; // 명사형 전성 어미
ETM = 4; // 관형형 전성 어미
XPN = 43; // 체언 접두사
XSN = 46; // 명사 파생 접미사
XSV = 47; // 동사 파생 접미사
XSA = 45; // 형용사 파생 접미사
XR = 44; // 어근
SF = 30; // 마침표,물음표,느낌표
SP = 35; // 쉼표,가운뎃점,콜론,빗금
SS = 36; // 따옴표,괄호표,줄표
SE = 29; // 줄임표
SO = 34; // 붙임표(물결,숨김,빠짐)
SW = 37; // 기타기호 (논리수학기호,화폐기호)
SL = 32; // 외국어
SH = 31; // 한자
SN = 33; // 숫자
}
}
// 텍스트 조각
message TextSpan {
// 텍스트 조각의 내용
string content = 1;
// 텍스트 조각의 위치
// EncodingType에 따라서 위치의 값이 달라진다.
int32 begin_offset = 2;
// 길이
int32 length = 3;
}
문장, 어절, 형태소의 구조
분석 결과는 크게 다음과 같은 구성을 하고 있습니다. 문장은 어절의 배열이고, 어절은 형태소의 배열입니다. 각 블럭은 TextSpan 이라는 단위로 표현되는데, 잘게 자른 문자열의 연속을 표현하고, 위치 정보를 가지고 있습니다. 길이 정보도 포함하고 있습니다.
classDiagram
Sentence *-- Token
Token *-- Morpheme
Sentence *-- TextSpan
Token *-- TextSpan
Morpheme *-- TextSpan
class Sentence {
list~Token~ tokens
TextSpan text
String refined
}
class Token {
list~Morpheme~ morphemes
TextSpan text
Strin glemma
String tagged
String modified
}
class Morpheme {
tag
probability
outOfVocab
}
class TextSpan {
String content
int beginOffset
int length
}
형태소 분석의 결과
위 문장을 분석한 결과는 다음과 같습니다.
위 문장에서 모두는과 늘 사이에 공백이 3개 포함되어 있습니다.
{
"sentences": [
{
"text": {
"content": "우리 모두는 늘 꿈을 꾸고 조금씩 만들어 가는 하루를 쌓아간다.",
"beginOffset": 0,
"length": 37
},
"tokens": [
{
"text": {
"content": "우리",
"beginOffset": 0,
"length": 2
},
"morphemes": [
{
"text": {
"content": "우리",
"beginOffset": 0,
"length": 2
},
"tag": "NP",
"probability": 0.983755946,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "우리",
"tagged": "우리/NP"
},
{
"text": {
"content": "모두는",
"beginOffset": 3,
"length": 3
},
"morphemes": [
{
"text": {
"content": "모두",
"beginOffset": 3,
"length": 2
},
"tag": "NNG",
"probability": 0.978339255,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "는",
"beginOffset": 5,
"length": 1
},
"tag": "JX",
"probability": 0.99596709,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "모두",
"tagged": "모두/NNG+는/JX"
},
{
"text": {
"content": "늘",
"beginOffset": 9,
"length": 1
},
"morphemes": [
{
"text": {
"content": "늘",
"beginOffset": 9,
"length": 1
},
"tag": "MAG",
"probability": 0.990521491,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "늘",
"tagged": "늘/MAG"
},
{
"text": {
"content": "꿈을",
"beginOffset": 11,
"length": 2
},
"morphemes": [
{
"text": {
"content": "꿈",
"beginOffset": 11,
"length": 1
},
"tag": "NNG",
"probability": 0.978667676,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "을",
"beginOffset": 12,
"length": 1
},
"tag": "JKO",
"probability": 0.998493552,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "꿈",
"tagged": "꿈/NNG+을/JKO"
},
{
"text": {
"content": "꾸고",
"beginOffset": 14,
"length": 2
},
"morphemes": [
{
"text": {
"content": "꾸",
"beginOffset": 14,
"length": 1
},
"tag": "VV",
"probability": 0.979055166,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "고",
"beginOffset": 15,
"length": 1
},
"tag": "EC",
"probability": 0.98225385,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "꾸",
"tagged": "꾸/VV+고/EC"
},
{
"text": {
"content": "조금씩",
"beginOffset": 17,
"length": 3
},
"morphemes": [
{
"text": {
"content": "조금",
"beginOffset": 17,
"length": 2
},
"tag": "NNG",
"probability": 0.976339459,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "씩",
"beginOffset": 19,
"length": 1
},
"tag": "XSN",
"probability": 0.954161286,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "조금",
"tagged": "조금/NNG+씩/XSN"
},
{
"text": {
"content": "만들어",
"beginOffset": 21,
"length": 3
},
"morphemes": [
{
"text": {
"content": "만들",
"beginOffset": 21,
"length": 2
},
"tag": "VV",
"probability": 0.976726532,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "어",
"beginOffset": 23,
"length": 1
},
"tag": "EC",
"probability": 0.984725058,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "만들",
"tagged": "만들/VV+어/EC"
},
{
"text": {
"content": "가는",
"beginOffset": 25,
"length": 2
},
"morphemes": [
{
"text": {
"content": "가",
"beginOffset": 25,
"length": 1
},
"tag": "VX",
"probability": 0.766881585,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "는",
"beginOffset": 26,
"length": 1
},
"tag": "ETM",
"probability": 0.997791588,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "가",
"tagged": "가/VX+는/ETM"
},
{
"text": {
"content": "하루를",
"beginOffset": 28,
"length": 3
},
"morphemes": [
{
"text": {
"content": "하루",
"beginOffset": 28,
"length": 2
},
"tag": "NNG",
"probability": 0.983489573,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "를",
"beginOffset": 30,
"length": 1
},
"tag": "JKO",
"probability": 0.99864924,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "하루",
"tagged": "하루/NNG+를/JKO"
},
{
"text": {
"content": "쌓아",
"beginOffset": 32,
"length": 2
},
"morphemes": [
{
"text": {
"content": "쌓",
"beginOffset": 32,
"length": 1
},
"tag": "VV",
"probability": 0.96607554,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "아",
"beginOffset": 33,
"length": 1
},
"tag": "EC",
"probability": 0.990258396,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "쌓",
"tagged": "쌓/VV+아/EC"
},
{
"text": {
"content": "간다.",
"beginOffset": 34,
"length": 3
},
"morphemes": [
{
"text": {
"content": "가",
"beginOffset": 34,
"length": 1
},
"tag": "VX",
"probability": 0.790500104,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": "ㄴ다",
"beginOffset": 34,
"length": 2
},
"tag": "EF",
"probability": 0.983418167,
"outOfVocab": "IN_WORD_EMBEDDING"
},
{
"text": {
"content": ".",
"beginOffset": 36,
"length": 1
},
"tag": "SF",
"probability": 0.996877491,
"outOfVocab": "IN_WORD_EMBEDDING"
}
],
"lemma": "가",
"tagged": "가/VX+ㄴ다/EF+./SF"
}
],
"refined": "우리 모두는 늘 꿈을 꾸고 조금씩 만들어 가는 하루를 쌓아 간다."
}
],
"language": "ko_KR"
}
형태소(Morpheme) 객체
형태소 객체는 아래와 같습니다.
// 형태소
message Morpheme {
// The sentence text.
TextSpan text = 1;
// 형태소 태그
Tag tag = 2;
// 형태소 분석 결과 확률
float probability = 3;
// 사전에 없는 단어 표시
OutOfVocab out_of_vocab = 5;
// 사용된 사용자 사전의 이름
optional string custom_dict_name = 6;
// 사전에 없는 단어 정보 처리 결과
enum OutOfVocab {
IN_WORD_EMBEDDING = 0; // 워드 임베딩에 포함된 내용
OUT_OF_VOCAB = 1; // 자동 추측, 미등록 단어
IN_CUSTOM_DICT = 2; // 사용자 제공 사전에 있는 내용
IN_BUILTIN_DICT = 3; // 기본 사전에 포함된 내용
}
}
| 변수 | 서브 변수 | 설명 |
|---|---|---|
| text | content | 분절된 형태의 내용입니다. |
| begin_offset | 분절 형태의 시작 위치를 나타냅니다. 활용, 축약, 생략이 이뤄진 경우에 복원된 형태는 원 음절의 위치를 나타냅니다. | |
| length | 분절된 형태의 길이입니다. | |
| tag | 아래 품사표를 참고해주세요. | |
| probability | 딥러닝 엔진이 softmax로 수행한 결과의 값을 출력해줍니다. 딥러닝에서 태깅에 대한 확신을 나타냅니다. |
|
| out_of_vocab | 이 단어의 추측에 대한 근거입니다. | |
| custom_dict_name | 요청 시점에 하나 이상의 사전을 참고할 수 있도록 합니다. 따라서 어떤 사전에 따라서 단어를 선정했는지 확인할 필요가 있습니다. 사용된 사전의 이름을 반환합니다. |
학습하지 않는 단어
딥러닝 자연어 처리에서 늘 학습하지 않은 단어들은 해결해야할 문제입니다. 바른은 학습하지 않은 단어들, 특히 신조어를 자동으로 추출해주는 능력을 가지고 있습니다.
| enum | 값 | 설명 |
|---|---|---|
| IN_WORD_EMBEDDING | 0 | 학습에 사용한 값입니다. |
| OUT_OF_VOCAB | 1 | 미등록 단어입니다. 자동으로 추축하여 품사를 지정합니다. |
| IN_CUSTOM_DICT | 2 | 사용자 사전에서 단어를 발견한 경우입니다. custom_dict_name을 이용해서 조회해서 적용된 사전의 이름을 알아낼 수 있습니다. |
| IN_BUILTIN_DICT | 3 | 기본 사전에서 단어를 발견했습니다. |
도움이 되었나요?