/**
* Data 구조를 모아놓은 module입니다.
*
* @module koalanlp/data
* @example
* import { Morpheme, Word, Sentence, SyntaxTree, DepEdge, RoleEdge, Entity, CoreferenceGroup } from 'koalanlp/data';
*/
import _ from 'underscore';
import {CoarseEntityType, DependencyTag, PhraseTag, POS, RoleType} from "./types";
import {JVM} from "./jvm";
import {assert, getOrUndefined, isDefined, typeCheck} from './common';
/** @private */
function writeonlyonce(target, defValue, ...properties) {
for (const property of properties) {
let value = undefined;
let descriptor = {};
descriptor.get = () => {
return (!isDefined(value)) ? defValue : value
};
descriptor.set = (newValue) => {
if(value === newValue)
return;
if(isDefined(value))
throw TypeError(`${property} 변수는 1회 초기화된 이후에는 변경할 수 없습니다. (현재 값 ${value.toString()}, 새 값 ${newValue.toString()})`);
value = newValue;
};
Object.defineProperty(target, property, descriptor);
}
}
/** @private */
function replaceableifempty(target, ...properties) {
for (const property of properties) {
let value = Object.freeze([]);
let descriptor = {};
descriptor.get = () => value;
descriptor.set = (newValue) => {
if(value === newValue)
return;
if(value.length > 0)
throw TypeError(`${property} 변수는 1회 초기화된 이후에는 변경할 수 없습니다. (현재 값 ${value}, 새 값 ${newValue})`);
value = Object.freeze(newValue);
};
Object.defineProperty(target, property, descriptor);
}
}
/**
* JavaWrapper class
* @private
*/
class JavaWrappable {
/**
* @private
*/
_reference;
_initReference() {
throw Error("구현이 필요합니다!");
}
equals(other){
throw Error("구현이 필요합니다!");
}
get reference() {
if (!isDefined(this._reference))
this._reference = this._initReference();
return this._reference;
}
set reference(value) {
if (isDefined(this._reference))
throw TypeError("reference는 설정된 다음 변경할 수 없습니다.");
this._reference = value;
}
}
/* istanbul ignore next */
/**
* Immutable Array.
* @private
* @template {T}
*/
class ImmutableArray extends JavaWrappable {
/**
* Items.
* @private
* @type {Array.<T>}
*/
_items;
/**
* Immutable Array 생성.
* @param {Array.<T>} items
* @param {*} type
* @return {ImmutableArray.<T>}
* @template {T}
*/
constructor(items, ...type) {
super();
typeCheck(items, ...type);
Object.defineProperty(this, '_items', {
value: Object.freeze(items),
writable: false,
configurable: false
});
return new Proxy(this, {
get: function(target, name){
if(isDefined(target[name]))
return target[name];
else if(typeof name !== 'symbol' && !isNaN(name)) {
name = parseInt(name);
if (name >= 0) return target._items[name];
else return target._items[target.length + name];
}else
return undefined;
},
set: function(target, name, value){
if(typeof name !== 'symbol' && !isNaN(name))
return false;
else
return Reflect.set(...arguments);
}
});
}
/**
* The length of array
* @returns {Number}
*/
get length(){
return this._items.length;
}
/**
* @returns {Iterator.<T>} Iterator를 반환합니다
*/
[Symbol.iterator](){
return this._items[Symbol.iterator]();
}
/**
* 두 대상이 Java KoalaNLP 조건에서 같은지 확인합니다.
* (Javascript는 == 또는 === 연산자를 override할 수 없어 별도로 제공합니다.)
*
* @param {T} other 확인할 다른 대상.
* @return {boolean} 같다면 true.
*/
equals(other) {
if (typeof(other) === typeof(this) && other.length === this.length){
for (const [a, b] of _.zip(this._items, other)){
if (!a.equals(b)) return false;
}
return true;
}else return false;
}
/**
* @see Array#indexOf
* @param value 찾을 값
* @returns {number}
*/
indexOf(value){
return this._items.indexOf(value);
}
/**
* [equals] 함수를 사용하여 주어진 값과 값이 동일한 첫 index를 찾습니다.
*
* ** (참고) ** Javascript의 indexOf 함수는 strict equality를 사용하여 값이 같은 경우가 아닌 reference가 같은 경우를 조회합니다.
*
* @param {T} value 찾을 값.
* @returns {number} 찾은 첫번째 값의 index. 없으면 -1
*/
indexOfValue(value){
return this.findIndex((x) => x.equals(value));
}
/**
* @see Array#lastIndexOf
* @param value 찾을 값
* @returns {number}
*/
lastIndexOf(value){
return this._items.indexOf(value);
}
/**
* [equals] 함수를 사용하여 주어진 값과 값이 동일한 마지막 index를 찾습니다.
*
* ** (참고) ** Javascript의 indexOf 함수는 strict equality를 사용하여 값이 같은 경우가 아닌 reference가 같은 경우를 조회합니다.
*
* @param {T} value 찾을 값.
* @returns {number} 찾은 마지막 값의 index. 없으면 -1
*/
lastIndexOfValue(value){
return this.findLastIndex((x) => x.equals(value));
}
/**
* @see Array#includes
* @param value 찾을 값
* @returns {boolean}
*/
includes(value){
return this._items.includes(value);
}
/**
* [equals] 함수를 사용하여 주어진 값과 동일한 값이 있는지 확인합니다.
*
* ** (참고) ** Javascript의 includes 함수는 Same Value Zero를 사용하여 값이 같은 두 object라도 reference가 다르면 다르다고 판단합니다.
*
* @param {T} value 찾을 값.
* @returns {boolean} 값이 있으면 true
*/
includesValue(value){
return this.indexOfValue(value) !== -1;
}
/**
* @see Array#entries
* @returns {Iterator.<T>}
*/
entries(){
return this._items.entries();
}
/**
* @see Array#every
* @param callback
* @param thisArg
* @returns {boolean}
*/
every(callback, thisArg){
return this._items.every(callback, thisArg);
}
/**
* @see Array#filter
* @param callback
* @param thisArg
* @returns {Array.<T>}
*/
filter(callback, thisArg){
return this._items.filter(callback, thisArg);
}
/**
* @see Array#find
* @param predicate
* @param thisArg
* @returns {T}
*/
find(predicate, thisArg){
return this._items.find(predicate, thisArg);
}
/**
* @see Array#findIndex
* @param predicate
* @param thisArg
* @returns {number}
*/
findIndex(predicate, thisArg){
return this._items.findIndex(predicate, thisArg);
}
/**
* 주어진 조건을 만족하는 마지막 값의 index를 찾습니다.
* @param predicate
* @returns {number}
*/
findLastIndex(predicate){
return _.findLastIndex(this._items, predicate);
}
/**
* @see Array#forEach
* @param callback
* @param thisArg
*/
forEach(callback, thisArg){
return this._items.forEach(callback, thisArg);
}
/**
* @see Array#map
* @param callback
* @param thisArg
* @returns {Array}
*/
map(callback, thisArg){
return this._items.map(callback, thisArg);
}
/**
* @see Array#reduce
* @param callback
* @param initialValue
* @returns {*}
*/
reduce(callback, initialValue){
return this._items.reduce(callback, initialValue);
}
/**
* @see Array#reduceRight
* @param callback
* @param initialValue
* @returns {*}
*/
reduceRight(callback, initialValue){
return this._items.reduceRight(callback, initialValue);
}
/**
* @see Array#slice
* @param start
* @param end
* @returns {Array.<T>}
*/
slice(start, end){
return this._items.slice(start, end);
}
/**
* @see Array#some
* @param callback
* @param thisArg
* @returns {boolean}
*/
some(callback, thisArg){
return this._items.some(callback, thisArg);
}
/**
* @see Array#values
* @returns {Iterator.<T>}
*/
values(){
return this._items.values();
}
/**
* Javascript Array로 변환합니다. (변경불가능 상태)
* @returns {Array.<T>}
*/
toArray(){
return this._items;
}
}
/**
* 개체명 분석 결과를 저장할 [Property] class
*
* ## 참고
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Morpheme#entities|Morpheme#entities} 형태소가 속하는 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Word#entities|Word#entities} 어절에 연관된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#entities|Sentence#entities} 문장에 포함된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @augments ImmutableArray.<Morpheme>
*/
export class Entity extends ImmutableArray {
_surface;
_label;
_fineLabel;
_originalLabel;
/**
* 이 개체명과 공통된 대상을 지칭하는 공통 지시어 또는 대용어들의 묶음을 제공합니다.
*
* **[참고]**
*
* **공지시어 해소** 는 문장 내 또는 문장 간에 같은 대상을 지칭하는 어구를 찾아 묶는 분석과정입니다.
*
* 예) '삼성그룹의 계열사인 삼성물산은 같은 그룹의 계열사인 삼성생명과 함께'라는 문장에서
*
* * '삼성그룹'과 '같은 그룹'을 찾아 묶는 것을 말합니다.
*
* **영형대용어 분석** 은 문장에서 생략된 기능어를 찾아 문장 내 또는 문장 간에 언급되어 있는 어구와 묶는 분석과정입니다.
*
* 예) '나는 밥을 먹었고, 영희도 먹었다'라는 문장에서,
*
* * '먹었다'의 목적어인 '밥을'이 생략되어 있음을 찾는 것을 말합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.CorefResolver|CorefResolver} 공지시어 해소, 대용어 분석기 interface
* * {@link module:koalanlp/data.Sentence#corefGroups|Sentence#corefGroups} 문장 내에 포함된 개체명 묶음 [CoreferenceGroup]들의 목록을 반환하는 API
* * {@link module:koalanlp/data.CoreferenceGroup|CoreferenceGroup} 동일한 대상을 지칭하는 개체명을 묶는 API
*
* @type {CoreferenceGroup}
*/
corefGroup;
/**
* 개체명 분석 결과를 저장합니다.
* @param {!Object} value 개체명 분석 결과 객체
* @param {!string} value.surface 개체명의 표면형 문자열.
* @param {!string} value.label 개체명 대분류 값, [CoarseEntityType]에 기록된 개체명 중 하나의 name.
* @param {!string} value.fineLabel 개체명 세분류 값으로, [label]으로 시작하는 문자열.
* @param {!Morpheme[]} value.morphemes 개체명을 이루는 형태소의 목록
* @param {string} [value.originalLabel=undefined] 원본 분석기가 제시한 개체명 분류의 값.
*/
constructor(value) {
typeCheck([value.surface, value.fineLabel], 'string');
typeCheck([value.label], 'string', 'CoarseEntityType');
typeCheck([value.originalLabel], 'undefined', 'string');
super(value.morphemes, 'Morpheme');
writeonlyonce(this, undefined, 'corefGroup');
this._surface = value.surface;
this._label = (value.label instanceof CoarseEntityType) ? value.label.tagname : value.label;
this._fineLabel = value.fineLabel;
this._originalLabel = value.originalLabel;
for (const morph of this) {
morph.entities.push(this);
}
}
/**
* 개체명의 표면형 문자열.
* @type !string
*/
get surface() {
return this._surface;
}
/**
* @return {!string} 개체명의 표면형 문자열.
*/
getSurface() {
return this.surface;
}
/**
* 개체명 대분류 값, [CoarseEntityType]에 기록된 개체명 중 하나.
* @type !CoarseEntityType
*/
get label() {
return CoarseEntityType.withName(this._label);
}
/**
* @return {!CoarseEntityType} 개체명 대분류 값, [CoarseEntityType]에 기록된 개체명 중 하나.
*/
getLabel() {
return this.label;
}
/**
* 개체명 세분류 값으로, [label]으로 시작하는 문자열.
* @type !string
*/
get fineLabel() {
return this._fineLabel;
}
/**
* @return {!string} 개체명 세분류 값으로, [label]으로 시작하는 문자열.
*/
getFineLabel() {
return this.fineLabel;
}
/**
* 원본 분석기가 제시한 개체명 분류의 값. 기본값은 null.
* @type string
*/
get originalLabel() {
return this._originalLabel;
}
/**
* 이 개체명과 공통된 대상을 지칭하는 공통 지시어 또는 대용어들의 묶음을 제공합니다.
*
* **[참고]**
*
* **공지시어 해소** 는 문장 내 또는 문장 간에 같은 대상을 지칭하는 어구를 찾아 묶는 분석과정입니다.
*
* 예) '삼성그룹의 계열사인 삼성물산은 같은 그룹의 계열사인 삼성생명과 함께'라는 문장에서
*
* * '삼성그룹'과 '같은 그룹'을 찾아 묶는 것을 말합니다.
*
* **영형대용어 분석** 은 문장에서 생략된 기능어를 찾아 문장 내 또는 문장 간에 언급되어 있는 어구와 묶는 분석과정입니다.
*
* 예) '나는 밥을 먹었고, 영희도 먹었다'라는 문장에서,
*
* * '먹었다'의 목적어인 '밥을'이 생략되어 있음을 찾는 것을 말합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.CorefResolver|CorefResolver} 공지시어 해소, 대용어 분석기 interface
* * {@link module:koalanlp/data.Sentence#corefGroups|Sentence#corefGroups} 문장 내에 포함된 개체명 묶음 [CoreferenceGroup]들의 목록을 반환하는 API
* * {@link module:koalanlp/data.CoreferenceGroup|CoreferenceGroup} 동일한 대상을 지칭하는 개체명을 묶는 API
*
* @return {CoreferenceGroup} 공통된 대상을 묶은 [CoreferenceGroup]. 없다면 null.
*/
getCorefGroup() {
return this.corefGroup;
}
/**
* @return {string} 원본 분석기가 제시한 개체명 분류의 값. 기본값은 null.
*/
getOriginalLabel() {
return this.originalLabel;
}
_initReference() {
return JVM.koalaClassOf('data', 'Entity')(
this.surface,
JVM.koalaEnumOf('CoarseEntityType', this._label),
this.fineLabel,
JVM.listOf(this.map((m) => m.reference)),
this.originalLabel
);
}
/**
* @inheritDoc
*/
equals(other) {
return this._label === other._label &&
this.fineLabel === other.fineLabel &&
super.equals(other);
}
/**
* @inheritDoc
*/
toString() {
return `${this._label}(${this.fineLabel}; '${this.surface}')`
}
}
/**
* 공지시어 해소 또는 대용어 분석 결과를 저장할 class입니다.
*
* ## 참고
*
* **공지시어 해소** 는 문장 내 또는 문장 간에 같은 대상을 지칭하는 어구를 찾아 묶는 분석과정입니다.
*
* 예) '삼성그룹의 계열사인 삼성물산은 같은 그룹의 계열사인 삼성생명과 함께'라는 문장에서
*
* * '삼성그룹'과 '같은 그룹'을 찾아 묶는 것을 말합니다.
*
* **영형대용어 분석** 은 문장에서 생략된 기능어를 찾아 문장 내 또는 문장 간에 언급되어 있는 어구와 묶는 분석과정입니다.
*
* 예) '나는 밥을 먹었고, 영희도 먹었다'라는 문장에서,
*
* * '먹었다'의 목적어인 '밥을'이 생략되어 있음을 찾는 것을 말합니다.
*
* 아래를 참고해보세요.
* * {@link module:koalanlp/proc.CorefResolver|CorefResolver} 공지시어 해소, 대용어 분석기 interface
* * {@link module:koalanlp/data.Sentence#corefGroups|Sentence#corefGroups} 문장 내에 포함된 개체명 묶음 [CoreferenceGroup]들의 목록을 반환하는 API
* * {@link module:koalanlp/data.Entity#corefGroup|Entity#corefGroup} 각 개체명을 묶어 같은 지시 대상을 갖는 묶음인 [CoreferenceGroup]를 가져오는 API
*
* @augments ImmutableArray.<Entity>
*/
export class CoreferenceGroup extends ImmutableArray {
/**
* 공지시어 해소 또는 대용어 분석 결과를 저장합니다.
* @param {Entity[]} entities 묶음에 포함되는 개체명들의 목록
*/
constructor(entities) {
super(entities, 'Entity');
for (const entity of this) {
entity.corefGroup = this;
}
}
_initReference() {
return JVM.koalaClassOf('data', 'CoreferenceGroup')(
JVM.listOf(this.map((e) => e.reference))
);
}
}
/**
* 트리 구조를 저장할 [Property]입니다. {@link module:koalanlp/data.Word|Word}를 묶어서 표현하는 구조에 적용됩니다.
*
* @augments ImmutableArray.<Tree>
*/
export class Tree extends ImmutableArray {
_label;
_terminal;
/**
* 부모 노드를 반환합니다.
* * 부모 노드가 초기화되지 않은 경우 null을 반환합니다.
* @type {Tree}
*/
parent;
/**
* 트리 형태의 구조를 저장합니다.
* @param {!Object} value Tree 값 객체
* @param {!string} value.label 트리에 붙어있는 표지자입니다. null일 수 없습니다.
* @param {Word} value.terminal 트리의 노드에서 연결되는 [Word]
* @param {Tree[]} value.children 트리/DAG의 자식 노드들
*/
constructor(value) {
typeCheck([value.label], 'string');
typeCheck([value.terminal], 'undefined', 'Word');
super(value.children, 'SyntaxTree', 'Tree');
writeonlyonce(this, undefined, 'parent');
this._label = value.label;
this._terminal = value.terminal;
}
get label() {
throw Error("구현이 필요합니다!")
}
/**
* @return {*} 트리에 붙어있는 표지자입니다. null일 수 없습니다.
*/
getLabel() {
return this.label;
}
/**
* 트리의 노드에서 연결되는 [Word] 또는 null
* @type Word
*/
get terminal() {
return this._terminal
}
/**
* @return {Word} 트리의 노드에서 연결되는 [Word] 또는 null
*/
getTerminal() {
return this.terminal;
}
/**
* 이 노드가 최상위 노드인지 확인합니다.
* @return {boolean} 최상위 노드인 경우 true
*/
isRoot() {
return !isDefined(this.parent);
}
/**
* 이 노드가 (terminal node를 제외하고) 자식 노드를 갖는지 확인합니다.
* * 구문분석 구조에서 terminal node는 [Word]가 됩니다.
* @return {boolean} 자식노드가 있다면 True
*/
hasNonTerminals() {
return this.length > 0;
}
/**
* 이 노드에서 출발하는 말단 노드를 모두 반환합니다.
* * 구문분석 구조에서 말단 노드는 [Word]가 됩니다.
* @returns {Array.<Word>}
*/
getTerminals() {
let leaves = this.reduce((acc, child) => acc.concat(child.getTerminals()), []);
if (this.terminal !== undefined) {
leaves.push(this.terminal);
}
return leaves.sort((x, y) => x.id - y.id);
}
/**
* @param {!number} [depth=0] 들여쓰기할 수준입니다. 숫자만큼 들여쓰기됩니다.
* @param {!string} [buffer=''] 텍스트 초기값입니다.
* @return {!string} 트리구조의 표현을 문자열로 돌려줍니다.
*/
getTreeString(depth = 0, buffer = '') {
buffer += "| ".repeat(depth);
buffer += this.toString();
for (const child of this) {
buffer += '\n';
buffer = child.getTreeString(depth + 1, buffer);
}
return buffer;
}
/**
* 부모 노드를 반환합니다.
* * 부모 노드가 초기화되지 않은 경우 null을 반환합니다.
* @return {Tree} 같은 타입의 부모 노드 또는 null
*/
getParent() {
return this.parent;
}
/**
* 이 노드의 Non-terminal 자식 노드를 모읍니다.
* * 이 함수는 읽기의 편의를 위한 syntactic sugar입니다. 즉 다음 구문은 동일합니다.
* @example
* ```javascript
* for (const item in x.getNonTerminals()){...}
* for (const item in x){...}
* ```
* @return {Tree[]} Non-terminal 자식노드들.
*/
getNonTerminals() {
return this.toArray();
}
/**
* @inheritDoc
*/
toString() {
return `${this._label}-Node(${this.terminal || ''})`
}
/**
* @inheritDoc
*/
equals(other) {
if(isDefined(this.terminal))
return this._label === other._label && this.terminal.equals(other.terminal) && super.equals(other);
else
return this._label === other._label && !isDefined(other.terminal) && super.equals(other);
}
}
/**
* 구문구조 분석의 결과를 저장할 [Property].
*
* ## 참고
*
* **구문구조 분석** 은 문장의 구성요소들(어절, 구, 절)이 이루는 문법적 구조를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는 2개의 절이 있습니다
*
* * 나는 밥을 먹었고
* * 영희는 짐을 쌌다
*
* 각 절은 3개의 구를 포함합니다
*
* * 나는, 밥을, 영희는, 짐을: 체언구
* * 먹었고, 쌌다: 용언구
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 구문구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#phrase|Word#phrase} 어절이 직접 속하는 가장 작은 구구조 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#syntaxTree|Sentence#syntaxTree} 전체 문장을 분석한 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 구구조의 형태 분류를 갖는 Enum 값
* @augments Tree
*/
export class SyntaxTree extends Tree {
_originalLabel;
/**
* 구문구조 분석의 결과를 생성합니다.
* @param {!Object} value SyntaxTree 값 객체
* @param {string|PhraseTag} value.label 구구조 표지자입니다. [PhraseTag] Enum의 name 값.
* @param {Word} [value.terminal=undefined] 현재 구구조에 직접 속하는 [Word]들. 중간 구문구조인 경우 leaf를 직접 포함하지 않으므로 undefined.
* @param {Tree[]} [value.children=undefined] 현재 구구조에 속하는 하위 구구조 [SyntaxTree]
* @param {string} [value.originalLabel=undefined] 원본 분석기의 표지자 String 값.
*/
constructor(value) {
typeCheck([value.label], 'string', 'PhraseTag');
typeCheck([value.originalLabel], 'undefined', 'string');
value.children = value.children || [];
value.label = (value.label instanceof PhraseTag) ? value.label.tagname : value.label;
super(value);
this._originalLabel = value.originalLabel;
let term = this.terminal;
if (term !== undefined) {
term.phrase = this;
}
for (const child of this) {
child.parent = this;
}
}
_initReference() {
return JVM.koalaClassOf('data', 'SyntaxTree')(
JVM.koalaEnumOf('PhraseTag', this._label),
(this.terminal) ? this.terminal.reference : null,
JVM.listOf(this.map((t) => t.reference)),
this.originalLabel
);
}
/**
* 원본 분석기의 표지자 String 값. 기본값은 undefined.
* @type string
*/
get originalLabel() {
return this._originalLabel;
}
/**
* 원본 분석기의 표지자 String 값. 기본값은 undefined.
* @return {string} 원본 분석기의 표지자 String 값.
*/
getOriginalLabel() {
return this.originalLabel;
}
/**
* 구문구조 표지자
* @type PhraseTag
*/
get label() {
return PhraseTag.withName(this._label);
}
}
/**
* DAG Edge를 저장합니다.
*/
export class DAGEdge extends JavaWrappable {
_src;
_dest;
_label;
/**
* DAG Edge를 구성합니다.
* @param {!Object} value DAG Edge 값 객체
* @param {Word} value.src 시점
* @param {!Word} value.dest 종점
* @param {string} value.label 관계
*/
constructor(value) {
typeCheck([value.src], 'undefined', 'Word');
typeCheck([value.dest], 'Word');
typeCheck([value.label], 'undefined', 'string');
super();
this._src = value.src;
this._dest = value.dest;
this._label = value.label;
}
/**
* Edge의 시작점. 의존구문분석인 경우 지배소, 의미역인 경우 동사.
* @type Word
*/
get src() {
return this._src;
}
/**
* @return {Word} Edge의 시작점. 의존구문분석인 경우 지배소, 의미역인 경우 동사.
*/
getSrc() {
return this.src;
}
/**
* Edge의 종점. 의존구문분석인 경우 피지배소, 의미역인 경우 논항.
* @type Word
*/
get dest() {
return this._dest;
}
/**
* @return {Word} Edge의 종점. 의존구문분석인 경우 피지배소, 의미역인 경우 논항.
*/
getDest() {
return this.dest;
}
/**
* Edge가 나타내는 관계.
*/
get label() {
throw Error("구현이 필요합니다!");
}
/**
* Edge가 나타내는 관계.
*/
getLabel() {
return this.label;
}
/**
* @inheritDoc
*/
toString() {
return `${this._label || ''}('${this.src || 'ROOT'}' → '${this.dest}')`;
}
/**
* 두 DAG Edge가 같은지 비교합니다.
* @param other 비교할 대상
* @return {boolean} 같은 정보를 담고 있다면 true
*/
equals(other) {
return typeof(this) === typeof(other) && this._label === other._label &&
this.src.equals(other.src) && this.dest.equals(other.dest)
}
}
/**
* 의존구문구조 분석의 결과.
*
* ## 참고
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#dependentEdges|Word#dependentEdges} 어절이 직접 지배하는 하위 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/data.Word#governorEdge|Word#governorEdge} 어절이 지배당하는 상위 의존구조 [DepEdge]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#dependencies|Sentence#dependencies} 전체 문장을 분석한 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* @augments DAGEdge
*/
export class DepEdge extends DAGEdge {
_originalLabel;
_type;
/**
* 의존구문 구조를 생성합니다.
* @param {!Object} value DepEdge 값을 나타내는 객체.
* @param {Word} value.governor 의존구문구조의 지배소
* @param {!Word} value.dependent 의존구문구조의 피지배소
* @param {!string|PhraseTag} value.type 구문분석 표지자
* @param {string|DependencyTag} [value.depType=undefined] 의존구문구조 표지자
* @param {string} [value.originalLabel=undefined] 의존구문구조 표지자의 원본분석기 표기
*/
constructor(value) {
typeCheck([value.type], 'string', 'PhraseTag');
typeCheck([value.depType], 'undefined', 'string', 'DependencyTag');
typeCheck([value.originalLabel], 'undefined', 'string');
value.type = (value.type instanceof PhraseTag) ? value.type.tagname : value.type;
value.depType = (value.depType instanceof DependencyTag) ? value.depType.tagname : value.depType;
value.src = value.governor;
value.dest = value.dependent;
value.label = value.depType;
super(value);
this._type = value.type;
this._originalLabel = value.originalLabel;
if (isDefined(this.dest)) {
this.dest.governorEdge = this;
}
if (isDefined(this.src)) {
this.src.dependentEdges.push(this);
}
}
_initReference() {
return JVM.koalaClassOf('data', 'DepEdge')(
(isDefined(this.governor)) ? this.governor.reference : null,
this.dependent.reference,
JVM.koalaEnumOf('PhraseTag', this._type),
JVM.koalaEnumOf('DependencyTag', this._label),
this._originalLabel
)
}
/**
* 의존구조의 지배소 [Word]. 문장의 Root에 해당하는 경우 None.
* @type Word
*/
get governor() {
return this.src;
}
/**
* @return {Word} 의존구조의 지배소 [Word]. 문장의 Root에 해당하는 경우 None.
*/
getGovernor() {
return this.governor;
}
/**
* 의존구조의 피지배소 [Word]
* @type Word
*/
get dependent() {
return this.dest;
}
/**
* @return {Word} 의존구조의 피지배소 [Word]
*/
getDependent() {
return this.dependent;
}
/**
* @inheritDoc
* @type {DependencyTag}
*/
get label() {
return DependencyTag.withName(this._label);
}
/**
* 의존기능 표지자, [DependencyTag] Enum 값. 별도의 기능이 지정되지 않으면 undefined. (ETRI 표준안은 구구조+의존기능으로 의존구문구조를 표기함)
* @type DependencyTag
*/
get depType() {
return this.label;
}
/**
* @return {DependencyTag} 의존기능 표지자, [DependencyTag] Enum 값. 별도의 기능이 지정되지 않으면 undefined. (ETRI 표준안은 구구조+의존기능으로 의존구문구조를 표기함)
*/
getDepType() {
return this.depType;
}
/**
* 구구조 표지자, [PhraseTag] Enum 값 (ETRI 표준안은 구구조+의존기능으로 의존구문구조를 표기함)
* @type PhraseTag
*/
get type() {
return PhraseTag.withName(this._type);
}
/**
* @return {PhraseTag} 구구조 표지자, [PhraseTag] Enum 값 (ETRI 표준안은 구구조+의존기능으로 의존구문구조를 표기함)
*/
getType() {
return this.type;
}
/**
* 원본 분석기의 표지자 String 값. 기본값은 undefined.
* @type string
*/
get originalLabel() {
return this._originalLabel;
}
/**
* @return {string} 원본 분석기의 표지자 String 값. 기본값은 undefined.
*/
getOriginalLabel() {
return this.originalLabel;
}
/**
* @inheritDoc
*/
equals(other) {
return this._type === other._type && super.equals(other);
}
/**
* @inheritDoc
*/
toString() {
return `${this._type}${super.toString()}`;
}
}
/**
* 의미역 구조 분석의 결과.
*
* ## 참고
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#argumentRoles|Word#argumentRoles} 어절이 술어인 논항들의 [RoleEdge] 목록을 가져오는 API
* * {@link module:koalanlp/data.Word#predicateRoles|Word#predicateRoles} 어절이 논항인 [RoleEdge]의 술어를 가져오는 API
* * {@link module:koalanlp/data.Sentence#roles|Sentence#roles} 전체 문장을 분석한 의미역 구조 [RoleEdge]를 가져오는 API
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
* @augments DAGEdge
*/
export class RoleEdge extends DAGEdge {
_originalLabel;
_modifiers;
/**
* 의미역 구조를 생성합니다.
* @param {!Object} value RoleEdge의 값을 나타내는 객체.
* @param {!Word} value.predicate 의미역 구조의 술어
* @param {!Word} value.argument 의미역 구조의 논항
* @param {!string|RoleType} value.label 의미역 구조의 표지자
* @param {Word[]} [value.modifiers=undefined] 논항의 수식어구들
* @param {string} [value.originalLabel=undefined] 의미역 구조 표지자의 원본분석기 표기
*/
constructor(value) {
typeCheck([value.label], 'string', 'RoleType');
typeCheck([value.originalLabel], 'undefined', 'string');
value.modifiers = value.modifiers || [];
typeCheck(value.modifiers, 'Word');
assert(isDefined(value.predicate),
'[value.predicate]은 undefined일 수 없습니다.');
value.label = (value.label instanceof RoleType) ? value.label.tagname : value.label;
value.src = value.predicate;
value.dest = value.argument;
super(value);
this._modifiers = value.modifiers;
this._originalLabel = value.originalLabel;
if (isDefined(this.dest)) {
this.dest.predicateRoles.push(this);
}
if (isDefined(this.src)) {
this.src.argumentRoles.push(this);
}
}
_initReference() {
return JVM.koalaClassOf('data', 'RoleEdge')(
(isDefined(this.predicate)) ? this.predicate.reference : null,
this.argument.reference,
JVM.koalaEnumOf('RoleType', this._label),
JVM.listOf(this.modifiers.map((x) => x.reference)),
this._originalLabel
)
}
/**
* 의미역 구조에서 표현하는 동사 [Word]
* @type !Word
*/
get predicate() {
return this.src;
}
/**
* @return {!Word} 의미역 구조에서 표현하는 동사 [Word]
*/
getPredicate() {
return this.predicate;
}
/**
* 의미역 구조에서 서술된 논항 [Word]
* @type !Word
*/
get argument() {
return this.dest;
}
/**
* @return {!Word} 의미역 구조에서 서술된 논항 [Word]
*/
getArgument() {
return this.argument;
}
/**
* @inheritDoc
* @type {RoleType}
*/
get label() {
return RoleType.withName(this._label);
}
/**
* 논항의 수식어구들
* @type ReadonlyArray<Word>
*/
get modifiers() {
return Object.freeze(this._modifiers);
}
/**
* @return {ReadonlyArray<Word>} 논항의 수식어구들
*/
getModifiers() {
return this.modifiers;
}
/**
* 원본 분석기의 표지자 String 값. 기본값은 undefined.
* @type string
*/
get originalLabel() {
return this._originalLabel;
}
/**
* @return {string} 원본 분석기의 표지자 String 값. 기본값은 undefined.
*/
getOriginalLabel() {
return this.originalLabel;
}
/**
* @inheritDoc
*/
toString() {
return `${this._label}('${(isDefined(this.src)) ? this.src.surface : 'ROOT'}' → '${this.dest.surface}/${this.modifiers.map((w) => w.surface).join(' ')}')`;
}
}
/**
* 형태소를 저장하는 [Property] class입니다.
*
* ## 참고
*
* **형태소** 는 의미를 가지는 요소로서는 더 이상 분석할 수 없는 가장 작은 말의 단위로 정의됩니다.
*
* **형태소 분석** 은 문장을 형태소의 단위로 나누는 작업을 의미합니다.
*
* 예) '문장을 형태소로 나눠봅시다'의 경우,
*
* * 문장/일반명사, -을/조사,
* * 형태소/일반명사, -로/조사,
* * 나누-(다)/동사, -어-/어미, 보-(다)/동사, -ㅂ시다/어미
*
* 로 대략 나눌 수 있습니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Tagger|Tagger} 형태소 분석기의 최상위 Interface
* * {@link module:koalanlp/types.POS|POS} 형태소의 분류를 담은 Enum class
*/
export class Morpheme extends JavaWrappable {
_surface;
_tag;
_originalTag;
/**
* 형태소의 어절 내 위치
* @type {number}
*/
id;
/**
* 형태소의 상위 어절.
* @type {Word}
*/
word;
/**
* 형태소의 의미 어깨번호.
* @type {number}
*/
wordSense;
/**
* 개체명 분석을 했다면, 현재 형태소가 속한 개체명 값을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Word#entities|Word#entities} 어절에 연관된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#entities|Sentence#entities} 문장에 포함된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @type {Entity[]}
*/
entities = [];
/**
* 형태소를 생성합니다.
* @param {!Object} value 형태소 값 객체
* @param {!string} value.surface 형태소 표면형
* @param {!string|POS} value.tag 형태소 품사 태그
* @param {string} [value.originalTag=undefined] 형태소 품사 원본 표기
* @param {Object} [value.reference=undefined] Java 형태소 객체
*/
constructor(value) {
typeCheck([value.surface], 'string');
typeCheck([value.tag], 'string', 'POS');
typeCheck([value.originalTag], 'undefined', 'string');
super();
writeonlyonce(this, -1, 'id');
writeonlyonce(this, undefined, 'word', 'wordsense');
this._surface = value.surface;
this._tag = (value.tag instanceof POS) ? value.tag.tagname : value.tag;
this._originalTag = value.originalTag;
this.reference = value.reference;
if (isDefined(value.reference)) {
this.wordSense = getOrUndefined(this.reference.getWordSense());
}
}
_initReference() {
return JVM.koalaClassOf('data', 'Morpheme')(
this.surface,
JVM.koalaEnumOf('POS', this._tag),
this.originalTag
);
}
/**
* 형태소 표면형 String
* @type string
*/
get surface() {
return this._surface;
}
/**
* @return {string} 형태소 표면형 String
*/
getSurface() {
return this.surface;
}
/**
* 세종 품사표기
* @type POS
*/
get tag() {
return POS.withName(this._tag);
}
/**
* @return {POS} 세종 품사표기
*/
getTag() {
return this.tag;
}
/**
* 원본 형태소 분석기의 품사 String (없으면 undefined)
* @type string
*/
get originalTag() {
return this._originalTag;
}
/**
* @return {string} 원본 형태소 분석기의 품사 String (없으면 undefined)
*/
getOriginalTag() {
return this.originalTag;
}
/**
* @return {number} 형태소의 어절 내 위치입니다.
*/
getId() {
return this.id;
}
/**
* 다의어 분석 결과인, 이 형태소의 사전 속 의미/어깨번호 값을 돌려줍니다.
*
* 다의어 분석을 한 적이 없다면 undefined를 돌려줍니다.
*
* @return {number} 의미/어깨번호 값
*/
getWordSense() {
return this.wordSense;
}
/**
* 개체명 분석을 했다면, 현재 형태소가 속한 개체명 값을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Word#entities|Word#entities} 어절에 연관된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#entities|Sentence#entities} 문장에 포함된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
* @return {Entity[]} [Entity]의 목록입니다. 분석 결과가 없으면 빈 리스트
*/
getEntities() {
return this.entities;
}
/**
* @return {Word} 이 형태소를 포함하는 단어를 돌려줍니다.
*/
getWord() {
return this.word;
}
/**
* 체언(명사, 수사, 대명사) 형태소인지 확인합니다.
* @return {boolean} 체언이라면 true
*/
isNoun() {
return this.tag.isNoun();
}
/**
* 용언(동사, 형용사) 형태소인지 확인합니다.
* @return {boolean} 용언이라면 true
*/
isPredicate() {
return this.tag.isPredicate();
}
/**
* 수식언(관형사, 부사) 형태소인지 확인합니다.
* @return {boolean} 수식언이라면 true
*/
isModifier() {
return this.tag.isModifier();
}
/**
* 관계언(조사) 형태소인지 확인합니다.
* @return {boolean} 관계언이라면 true
*/
isJosa() {
return this.tag.isPostPosition();
}
/**
* 세종 품사 [tag]가 주어진 품사 표기 [partialTag] 묶음에 포함되는지 확인합니다.
*
* 예) "N"은 체언인지 확인하고, "NP"는 대명사인지 확인
*
* ## 단축명령
*
* * 체언(명사, 수사, 대명사) {@link module:koalanlp/data.Morpheme#isNoun|Morpheme#isNoun}
* * 용언(동사, 형용사)는 {@link module:koalanlp/data.Morpheme#isPredicate|Morpheme#isPredicate}
* * 수식언(관형사, 부사)는 {@link module:koalanlp/data.Morpheme#isModifier|Morpheme#isModifier}
* * 관계언(조사)는 {@link module:koalanlp/data.Morpheme#isJosa|Morpheme#isJosa}
*
* **[참고]**
*
* * 분석불능범주(NA, NV, NF)는 체언(N) 범주에 포함되지 않습니다.
* * 세종 품사표기는 [POS](https://koalanlp.github.io/koalanlp/api/koalanlp/kr.bydelta.koala/-p-o-s/index.html) 를 참고하세요.
* * 품사 표기는 [비교표](https://docs.google.com/spreadsheets/d/1OGM4JDdLk6URuegFKXg1huuKWynhg_EQnZYgTmG4h0s/edit?usp=sharing) 에서 확인가능합니다.
*
* @param {!string} partialTag 포함 여부를 확인할 상위 형태소 분류 품사표기
* @return {boolean} 포함되는 경우 True.
*/
hasTag(partialTag) {
return this.tag.startsWith(partialTag);
}
/**
* 세종 품사 [tag]가 주어진 품사 표기들 [tags] 묶음들 중 하나에 포함되는지 확인합니다.
*
* 예) hasTagOneOf("N", "MM")의 경우, 체언 또는 관형사인지 확인합니다.
*
* ## 단축명령
*
* * 체언(명사, 수사, 대명사) {@link module:koalanlp/data.Morpheme#isNoun|Morpheme#isNoun}
* * 용언(동사, 형용사)는 {@link module:koalanlp/data.Morpheme#isPredicate|Morpheme#isPredicate}
* * 수식언(관형사, 부사)는 {@link module:koalanlp/data.Morpheme#isModifier|Morpheme#isModifier}
* * 관계언(조사)는 {@link module:koalanlp/data.Morpheme#isJosa|Morpheme#isJosa}
*
* **[참고]**
*
* * 분석불능범주(NA, NV, NF)는 체언(N) 범주에 포함되지 않습니다.
* * 세종 품사표기는 [POS](https://koalanlp.github.io/koalanlp/api/koalanlp/kr.bydelta.koala/-p-o-s/index.html) 를 참고하세요.
* * 품사 표기는 [비교표](https://docs.google.com/spreadsheets/d/1OGM4JDdLk6URuegFKXg1huuKWynhg_EQnZYgTmG4h0s/edit?usp=sharing) 에서 확인가능합니다.
*
* @param {string} tags 포함 여부를 확인할 상위 형태소 분류 품사표기들 (가변인자)
* @return {boolean} 하나라도 포함되는 경우 True.
*/
hasTagOneOf(...tags) {
return tags.some((t) => this.tag.startsWith(t));
}
/**
* 원본 품사 [originalTag]가 주어진 품사 표기 [partialTag] 묶음에 포함되는지 확인합니다.
*
* 예) 지정된 원본 품사가 없으면 (즉, None이면) false를 반환합니다.
*
* ## 단축명령
*
* * 체언(명사, 수사, 대명사) {@link module:koalanlp/data.Morpheme#isNoun|Morpheme#isNoun}
* * 용언(동사, 형용사)는 {@link module:koalanlp/data.Morpheme#isPredicate|Morpheme#isPredicate}
* * 수식언(관형사, 부사)는 {@link module:koalanlp/data.Morpheme#isModifier|Morpheme#isModifier}
* * 관계언(조사)는 {@link module:koalanlp/data.Morpheme#isJosa|Morpheme#isJosa}
*
* **[참고]**
*
* * 분석불능범주(NA, NV, NF)는 체언(N) 범주에 포함되지 않습니다.
* * 세종 품사표기는 [POS](https://koalanlp.github.io/koalanlp/api/koalanlp/kr.bydelta.koala/-p-o-s/index.html) 를 참고하세요.
* * 품사 표기는 [비교표](https://docs.google.com/spreadsheets/d/1OGM4JDdLk6URuegFKXg1huuKWynhg_EQnZYgTmG4h0s/edit?usp=sharing) 에서 확인가능합니다.
*
* @param {!string} partialTag 포함 여부를 확인할 상위 형태소 분류 품사표기
* @return {boolean} 포함되는 경우 True.
*/
hasOriginalTag(partialTag) {
if (isDefined(this.originalTag))
return this.originalTag.toUpperCase().startsWith(partialTag.toUpperCase());
else
return false;
}
/***
* 타 형태소 객체 [other]와 형태소의 표면형이 같은지 비교합니다.
* @param {Morpheme} other 표면형을 비교할 형태소
* @return {boolean} 표면형이 같으면 True
*/
equalsWithoutTag(other) {
return this.surface === other.surface;
}
/**
* @inheritDoc
*/
equals(other) {
return other instanceof Morpheme && this.surface === other.surface && this._tag === other._tag;
}
/**
* @inheritDoc
*/
toString() {
if (isDefined(this.originalTag)) {
return `${this.surface}/${this._tag}(${this.originalTag})`
} else {
return `${this.surface}/${this._tag}`
}
}
}
/**
* 어절을 저장합니다.
*
* @augments ImmutableArray.<Morpheme>
*/
export class Word extends ImmutableArray {
/**
* 표면형
* @private
* @type {string}
*/
_surface;
/**
* 어절의 문장 내 위치입니다.
* @type {number}
*/
id;
/**
* 구문분석을 했다면, 현재 어절이 속한 직속 상위 구구조(Phrase)를 돌려줍니다.
*
* **[참고]**
*
* **구문구조 분석** 은 문장의 구성요소들(어절, 구, 절)이 이루는 문법적 구조를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는 2개의 절이 있습니다
*
* * 나는 밥을 먹었고
* * 영희는 짐을 쌌다
*
* 각 절은 3개의 구를 포함합니다
*
* * 나는, 밥을, 영희는, 짐을: 체언구
* * 먹었고, 쌌다: 용언구
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 구문구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Sentence#syntaxTree|Sentence#syntaxTree} 전체 문장을 분석한 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/data.SyntaxTree|SyntaxTree} 구문구조를 저장하는 형태
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 구구조의 형태 분류를 갖는 Enum 값
* @type {SyntaxTree}
*/
phrase;
/**
* 의존구문분석을 했다면, 현재 어절이 지배소인 하위 의존구문 구조의 값을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#governorEdge|Word#governorEdge} 어절이 지배당하는 상위 의존구조 [DepEdge]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#dependencies|Sentence#dependencies} 전체 문장을 분석한 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
*
* @type {DepEdge[]}
*/
dependentEdges = [];
/**
*
* 의존구문분석을 했다면, 현재 어절이 의존소인 상위 의존구문 구조의 값을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#dependentEdges|Word#dependentEdges} 어절이 직접 지배하는 하위 의존구조 [DepEdge]의 목록를 가져오는 API
* * {@link module:koalanlp/data.Sentence#dependencies|Sentence#dependencies} 전체 문장을 분석한 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
* @type {DepEdge}
*/
governorEdge;
/**
* 의미역 분석을 했다면, 현재 어절이 술어로 기능하는 하위 의미역 구조의 목록을 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#predicateRoles|Word#predicateRoles} 어절이 논항인 [RoleEdge]의 술어를 가져오는 API
* * {@link module:koalanlp/data.Sentence#roles|Sentence#roles} 전체 문장을 분석한 의미역 구조 [RoleEdge]를 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @type {RoleEdge[]}
*/
argumentRoles = [];
/**
* 의미역 분석을 했다면, 현재 어절이 논항인 상위 의미역 구조를 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#argumentRoles|Word#argumentRoles} 어절이 술어인 논항들의 [RoleEdge] 목록을 가져오는 API
* * {@link module:koalanlp/data.Sentence#roles|Sentence#roles} 전체 문장을 분석한 의미역 구조 [RoleEdge]를 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @type {RoleEdge[]}
*/
predicateRoles = [];
/**
* 어절을 생성합니다.
* @param {!Object} value 어절 값 객체
* @param {!string} value.surface 어절의 표면형
* @param {!Morpheme[]} value.morphemes 어절에 포함되는 형태소의 목록
* @param {*} [value.reference=undefined] Java 어절 객체
*/
constructor(value) {
typeCheck([value.surface], 'string');
super(value.morphemes, 'Morpheme');
writeonlyonce(this, -1, 'id');
writeonlyonce(this, undefined, 'phrase', 'governorEdge');
this._surface = value.surface;
this.reference = value.reference;
for (const [i, morph] of this.entries()) {
morph.word = this;
morph.id = i;
}
}
_initReference() {
return JVM.koalaClassOf('data', 'Word')(
this.surface,
JVM.listOf(this.map((m) => m.reference))
)
}
/**
* 어절의 표면형 String.
* @type string
*/
get surface() {
return this._surface;
}
/**
* @return {string} 어절의 표면형 String.
*/
getSurface() {
return this.surface;
}
/**
* @return {number} 어절의 문장 내 위치입니다.
*/
getId() {
return this.id;
}
/**
* 개체명 분석을 했다면, 현재 어절이 속한 개체명 값을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Morpheme#entities|Morpheme#entities} 형태소를 포함하는 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#entities|Sentence#entities} 문장에 포함된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @type {Entity[]}
*/
get entities(){
let result = [];
for(const morpheme of this){
for(const entity of morpheme.entities){
if(!result.includes(entity)) {
result.push(entity);
}
}
}
return result;
};
/**
* 개체명 분석을 했다면, 현재 어절이 속한 개체명 값을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Morpheme#entities|Morpheme#entities} 형태소를 포함하는 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#entities|Sentence#entities} 문장에 포함된 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @return {Entity[]} [Entity]의 목록입니다. 분석 결과가 없으면 빈 리스트.
*/
getEntities() {
return this.entities;
}
/**
* 구문분석을 했다면, 현재 어절이 속한 직속 상위 구구조(Phrase)를 돌려줍니다.
*
* **[참고]**
*
* **구문구조 분석** 은 문장의 구성요소들(어절, 구, 절)이 이루는 문법적 구조를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는 2개의 절이 있습니다
*
* * 나는 밥을 먹었고
* * 영희는 짐을 쌌다
*
* 각 절은 3개의 구를 포함합니다
*
* * 나는, 밥을, 영희는, 짐을: 체언구
* * 먹었고, 쌌다: 용언구
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 구문구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Sentence#syntaxTree|Sentence#syntaxTree} 전체 문장을 분석한 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/data.SyntaxTree|SyntaxTree} 구문구조를 저장하는 형태
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 구구조의 형태 분류를 갖는 Enum 값
*
* @return {SyntaxTree} 어절의 상위 구구조 [SyntaxTree]. 분석 결과가 없으면 undefined.
*/
getPhrase() {
return this.phrase;
}
/**
* 의존구문분석을 했다면, 현재 어절이 지배소인 하위 의존구문 구조의 값을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#governorEdge|Word#governorEdge} 어절이 지배당하는 상위 의존구조 [DepEdge]를 가져오는 API
* * {@link module:koalanlp/data.Sentence#dependencies|Sentence#dependencies} 전체 문장을 분석한 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
*
* @return {DepEdge[]} 어절이 지배하는 의존구문구조 [DepEdge]의 목록. 분석 결과가 없으면 빈 리스트.
*/
getDependentEdges() {
return this.dependentEdges;
}
/**
* 의존구문분석을 했다면, 현재 어절이 의존소인 상위 의존구문 구조의 값을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#dependentEdges|Word#dependentEdges} 어절이 직접 지배하는 하위 의존구조 [DepEdge]의 목록를 가져오는 API
* * {@link module:koalanlp/data.Sentence#dependencies|Sentence#dependencies} 전체 문장을 분석한 의존구조 [DepEdge]의 목록을 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
*
* @return {DepEdge} 어절이 지배당하는 의존구문구조 [DepEdge]. 분석 결과가 없으면 None
*/
getGovernorEdge() {
return this.governorEdge;
}
/**
* 의미역 분석을 했다면, 현재 어절이 술어로 기능하는 하위 의미역 구조의 목록을 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#predicateRoles|Word#predicateRoles} 어절이 논항인 [RoleEdge]의 술어를 가져오는 API
* * {@link module:koalanlp/data.Sentence#roles|Sentence#roles} 전체 문장을 분석한 의미역 구조 [RoleEdge]를 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @return {RoleEdge[]} 어절이 술어로 기능하는 하위 의미역 구조 [RoleEdge]의 목록. 분석 결과가 없으면 빈 리스트.
*/
getArgumentRoles() {
return this.argumentRoles;
}
/**
* 의미역 분석을 했다면, 현재 어절이 논항인 상위 의미역 구조를 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#argumentRoles|Word#argumentRoles} 어절이 술어인 논항들의 [RoleEdge] 목록을 가져오는 API
* * {@link module:koalanlp/data.Sentence#roles|Sentence#roles} 전체 문장을 분석한 의미역 구조 [RoleEdge]를 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @return {RoleEdge[]} 어절이 논항인 상위 의미역 구조 [RoleEdge]. 분석 결과가 없으면 None.
*/
getPredicateRoles() {
return this.predicateRoles;
}
/**
* 품사분석 결과를, 1행짜리 String으로 변환합니다.
*
* 예) '나/NP+는/JX'
*
* **[참고]**
* * 세종 품사표기는 {@link module:koalanlp/types.POS|POS} 를 참고하세요.
*
* @return {string} 각 형태소별로 "표면형/품사" 형태로 기록하고 이를 +로 이어붙인 문자열.
*/
singleLineString() {
return this.map((m) => `${m.surface}/${m._tag}`).join('+')
}
/**
* @inheritDoc
*/
toString() {
return `${this.surface} = ${this.singleLineString()}`;
}
/**
* @inheritDoc
*/
equals(other) {
return super.equals(other) && this.surface === other.surface;
}
/***
* 타 어절 객체 [other]와 표면형이 같은지 비교합니다.
* @param {Word} other 표면형을 비교할 어절
* @return {boolean} 표면형이 같으면 True
*/
equalsWithoutTag(other) {
return this.surface === other.surface;
}
}
/**
* 문장을 저장하는 Class 입니다.
*
* @augments ImmutableArray.<Word>
*/
export class Sentence extends ImmutableArray {
/**
* 구문분석을 했다면, 최상위 구구조(Phrase)를 돌려줍니다.
*
* **[참고]**
*
* **구문구조 분석** 은 문장의 구성요소들(어절, 구, 절)이 이루는 문법적 구조를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는 2개의 절이 있습니다
*
* * 나는 밥을 먹었고
* * 영희는 짐을 쌌다
*
* 각 절은 3개의 구를 포함합니다
*
* * 나는, 밥을, 영희는, 짐을: 체언구
* * 먹었고, 쌌다: 용언구
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 구문구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#phrase|Word#phrase} 어절의 직속 상위 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/data.SyntaxTree|SyntaxTree} 구문구조를 저장하는 형태
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 구구조의 형태 분류를 갖는 Enum 값
* @type {SyntaxTree}
*/
syntaxTree;
/**
* 의존구문분석을 했다면, 문장에 포함된 모든 의존구조의 목록을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#governorEdge|Word#governorEdge} 어절이 지배당하는 상위 의존구조 [DepEdge]를 가져오는 API
* * {@link module:koalanlp/data.Word#dependentEdges|Word#dependentEdges} 어절이 직접 지배하는 하위 의존구조 [DepEdge]의 목록를 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
*
* @type {DepEdge[]}
*/
dependencies = [];
/**
* 의미역 분석을 했다면, 문장에 포함된 의미역 구조의 목록을 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#predicateRoles|Word#predicateRoles} 어절이 논항인 [RoleEdge]의 술어를 가져오는 API
* * {@link module:koalanlp/data.Word#argumentRoles|Word#argumentRoles} 어절이 술어인 [RoleEdge]의 논항들을 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @type {RoleEdge[]}
*/
roles = [];
/**
* 개체명 분석을 했다면, 문장의 모든 개체명 목록을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Morpheme#entities|Morpheme#entities} 형태소를 포함하는 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Word#entities|Word#entities} 해당 어절을 포함하는 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @type {Entity[]}
*/
entities = [];
/**
* 문장 내에 포함된 공통 지시어 또는 대용어들의 묶음을 제공합니다.
*
* **[참고]**
*
* **공지시어 해소** 는 문장 내 또는 문장 간에 같은 대상을 지칭하는 어구를 찾아 묶는 분석과정입니다.
*
* 예) '삼성그룹의 계열사인 삼성물산은 같은 그룹의 계열사인 삼성생명과 함께'라는 문장에서
*
* * '삼성그룹'과 '같은 그룹'을 찾아 묶는 것을 말합니다.
*
* **영형대용어 분석** 은 문장에서 생략된 기능어를 찾아 문장 내 또는 문장 간에 언급되어 있는 어구와 묶는 분석과정입니다.
*
* 예) '나는 밥을 먹었고, 영희도 먹었다'라는 문장에서,
*
* * '먹었다'의 목적어인 '밥을'이 생략되어 있음을 찾는 것을 말합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.CorefResolver|CorefResolver} 공지시어 해소, 대용어 분석기 interface
* * {@link module:koalanlp/data.Entity#corefGroup|Entity#corefGroup} 해당 개체명이 포함된 개체명 묶음 [CoreferenceGroup]을 반환하는 API
* * {@link module:koalanlp/data.CoreferenceGroup|CoreferenceGroup} 동일한 대상을 지칭하는 개체명을 묶는 API
*
* @type {CoreferenceGroup[]}
*/
corefGroups = [];
/**
* 문장을 만듭니다.
* @param {!Object|Word[]} value 자바 문장 객체 또는 어절의 Array.
*/
constructor(value) {
if (!Array.isArray(value)) {
let words = JVM.toJsArray(value,
(w) => new Word({
surface: w.getSurface(),
morphemes: JVM.toJsArray(w, (m) => new Morpheme({
surface: m.getSurface(),
tag: m.getTag().name(),
originalTag: m.getOriginalTag(),
reference: m
})),
reference: w
})
);
super(words, 'Word');
writeonlyonce(this, undefined, 'syntaxTree');
replaceableifempty(this, 'dependencies', 'roles', 'entities', 'corefGroups');
this.syntaxTree = this._reconSyntaxTree(value.getSyntaxTree());
this.dependencies = JVM.toJsArray(value.getDependencies(), (x) => this._getDepEdge(x));
this.roles = JVM.toJsArray(value.getRoles(), (x) => this._getRole(x));
this.entities = JVM.toJsArray(value.getEntities(), (x) => this._getEntity(x));
this.corefGroups = JVM.toJsArray(value.getCorefGroups(), (x) => this._getCorefGroup(x));
this.reference = value;
} else {
super(value, 'Word');
writeonlyonce(this, 'syntaxTree');
replaceableifempty(this, 'dependencies', 'roles', 'entities', 'corefGroups');
}
for (const [i, word] of this.entries()) {
word.id = i;
}
}
_getWord(jword) {
if (isDefined(jword)) {
return this[jword.getId()];
} else {
return undefined;
}
}
_getMorph(jmorph) {
if (isDefined(jmorph)) {
return this[jmorph.getWord().getId()][jmorph.getId()];
} else {
return undefined;
}
}
_reconSyntaxTree(jtree) {
if (!isDefined(jtree))
return undefined;
let term;
let nonTerms;
if (isDefined(jtree.getTerminal())) {
term = this._getWord(jtree.getTerminal());
}
if (jtree.hasNonTerminals()) {
nonTerms = JVM.toJsArray(jtree, (x) => this._reconSyntaxTree(x));
}
let tree = new SyntaxTree({
label: jtree.getLabel().name(),
terminal: term,
children: nonTerms,
originalLabel: getOrUndefined(jtree.getOriginalLabel())
});
tree.reference = jtree;
return tree;
}
_getDepEdge(e) {
let deptype = getOrUndefined(e.getDepType());
deptype = (isDefined(deptype)) ? deptype.name() : deptype;
let edge = new DepEdge({
governor: this._getWord(e.getGovernor()),
dependent: this._getWord(e.getDependent()),
type: e.getType().name(),
depType: deptype,
originalLabel: getOrUndefined(e.getOriginalLabel())
});
edge.reference = e;
return edge;
}
_getRole(e) {
let edge = new RoleEdge({
predicate: this._getWord(e.getPredicate()),
argument: this._getWord(e.getArgument()),
label: e.getLabel().name(),
modifiers: JVM.toJsArray(e.getModifiers(), (x) => this._getWord(x)),
originalLabel: getOrUndefined(e.getOriginalLabel())
});
edge.reference = e;
return edge;
}
_getEntity(e) {
let enty = new Entity({
surface: e.getSurface(),
label: e.getLabel().name(),
fineLabel: e.getFineLabel(),
morphemes: JVM.toJsArray(e, (x) => this._getMorph(x)),
originalLabel: getOrUndefined(e.getOriginalLabel())
});
enty.reference = e;
return enty;
}
_getCorefGroup(c) {
let coref = new CoreferenceGroup(
JVM.toJsArray(c, (e) => {
let referenced = this._getEntity(e);
return this.entities.find((enty) => enty.equals(referenced));
})
);
coref.reference = c;
return coref;
}
_initReference() {
let jsent = JVM.koalaClassOf('data', 'Sentence')(JVM.listOf(this.map((w) => w.reference)));
if (isDefined(this.syntaxTree)) {
jsent.setSyntaxTree(this.syntaxTree.reference);
}
if (this.roles.length > 0) {
jsent.setRoleEdges(JVM.listOf(this.roles.map((e) => e.reference)));
}
if (this.dependencies.length > 0) {
jsent.setDepEdges(JVM.listOf(this.dependencies.map((e) => e.reference)));
}
if (this.entities.length > 0) {
jsent.setEntities(JVM.listOf(this.entities.map((e) => e.reference)));
}
if (this.corefGroups.length > 0) {
jsent.setCorefGroups(JVM.listOf(this.corefGroups.map((e) => e.reference)));
}
return jsent;
}
/**
* 구문분석을 했다면, 최상위 구구조(Phrase)를 돌려줍니다.
*
* **[참고]**
*
* **구문구조 분석** 은 문장의 구성요소들(어절, 구, 절)이 이루는 문법적 구조를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는 2개의 절이 있습니다
*
* * 나는 밥을 먹었고
* * 영희는 짐을 쌌다
*
* 각 절은 3개의 구를 포함합니다
*
* * 나는, 밥을, 영희는, 짐을: 체언구
* * 먹었고, 쌌다: 용언구
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 구문구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#phrase|Word#phrase} 어절의 직속 상위 [SyntaxTree]를 가져오는 API
* * {@link module:koalanlp/data.SyntaxTree|SyntaxTree} 구문구조를 저장하는 형태
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 구구조의 형태 분류를 갖는 Enum 값
*
* @return {SyntaxTree} 최상위 구구조 [SyntaxTree]. 분석 결과가 없으면 undefined.
*/
getSyntaxTree() {
return this.syntaxTree;
}
/**
* 의존구문분석을 했다면, 문장에 포함된 모든 의존구조의 목록을 돌려줍니다.
*
* **[참고]**
*
* **의존구조 분석** 은 문장의 구성 어절들이 의존 또는 기능하는 관계를 분석하는 방법입니다.
*
* 예) '나는 밥을 먹었고, 영희는 짐을 쌌다'라는 문장에는
*
* 가장 마지막 단어인 '쌌다'가 핵심 어구가 되며,
*
* * '먹었고'가 '쌌다'와 대등하게 연결되고
* * '나는'은 '먹었고'의 주어로 기능하며
* * '밥을'은 '먹었고'의 목적어로 기능합니다.
* * '영희는'은 '쌌다'의 주어로 기능하고,
* * '짐을'은 '쌌다'의 목적어로 기능합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.Parser|Parser} 의존구조 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#governorEdge|Word#governorEdge} 어절이 지배당하는 상위 의존구조 [DepEdge]를 가져오는 API
* * {@link module:koalanlp/data.Word#dependentEdges|Word#dependentEdges} 어절이 직접 지배하는 하위 의존구조 [DepEdge]의 목록를 가져오는 API
* * {@link module:koalanlp/types.PhraseTag|PhraseTag} 의존구조의 형태 분류를 갖는 Enum 값 (구구조 분류와 같음)
* * {@link module:koalanlp/types.DependencyTag|DependencyTag} 의존구조의 기능 분류를 갖는 Enum 값
* * {@link module:koalanlp/data.DepEdge|DepEdge} 의존구문구조의 저장형태
* @return {DepEdge[]} 문장 내 모든 의존구문구조 [DepEdge]의 목록. 분석 결과가 없으면 빈 리스트.
*/
getDependencies() {
return this.dependencies;
}
/**
* 의미역 분석을 했다면, 문장에 포함된 의미역 구조의 목록을 돌려줌.
*
* **[참고]**
*
* **의미역 결정** 은 문장의 구성 어절들의 역할/기능을 분석하는 방법입니다.
*
* 예) '나는 밥을 어제 집에서 먹었다'라는 문장에는
*
* 동사 '먹었다'를 중심으로
*
* * '나는'은 동작의 주체를,
* * '밥을'은 동작의 대상을,
* * '어제'는 동작의 시점을
* * '집에서'는 동작의 장소를 나타냅니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.RoleLabeler|RoleLabeler} 의미역 분석을 수행하는 interface.
* * {@link module:koalanlp/data.Word#predicateRoles|Word#predicateRoles} 어절이 논항인 [RoleEdge]의 술어를 가져오는 API
* * {@link module:koalanlp/data.Word#argumentRoles|Word#argumentRoles} 어절이 술어인 [RoleEdge]의 논항들을 가져오는 API
* * {@link module:koalanlp/data.RoleEdge|RoleEdge} 의미역 구조를 저장하는 형태
* * {@link module:koalanlp/types.RoleType|RoleType} 의미역 분류를 갖는 Enum 값
*
* @return {RoleEdge[]} 문장 속의 모든 의미역 구조 [RoleEdge]의 목록. 분석 결과가 없으면 빈 리스트.
*/
getRoles() {
return this.roles;
}
/**
* 개체명 분석을 했다면, 문장의 모든 개체명 목록을 돌려줍니다.
*
* **[참고]**
*
* **개체명 인식** 은 문장에서 인물, 장소, 기관, 대상 등을 인식하는 기술입니다.
*
* 예) '철저한 진상 조사를 촉구하는 국제사회의 목소리가 커지고 있는 가운데, 트럼프 미국 대통령은 되레 사우디를 감싸고 나섰습니다.'에서, 다음을 인식하는 기술입니다.
*
* * '트럼프': 인물
* * '미국' : 국가
* * '대통령' : 직위
* * '사우디' : 국가
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.EntityRecognizer|EntityRecognizer} 개체명 인식기 interface
* * {@link module:koalanlp/data.Morpheme#entities|Morpheme#entities} 형태소를 포함하는 모든 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Word#entities|Word#entities} 해당 어절을 포함하는 [Entity]를 가져오는 API
* * {@link module:koalanlp/data.Entity|Entity} 개체명을 저장하는 형태
* * {@link module:koalanlp/types.CoarseEntityType|CoarseEntityType} [Entity]의 대분류 개체명 분류구조 Enum 값
*
* @return {Entity[]} 문장에 포함된 모든 [Entity]의 목록입니다.
*/
getEntities() {
return this.entities;
}
/**
* 문장 내에 포함된 공통 지시어 또는 대용어들의 묶음을 제공합니다.
*
* **[참고]**
*
* **공지시어 해소** 는 문장 내 또는 문장 간에 같은 대상을 지칭하는 어구를 찾아 묶는 분석과정입니다.
*
* 예) '삼성그룹의 계열사인 삼성물산은 같은 그룹의 계열사인 삼성생명과 함께'라는 문장에서
*
* * '삼성그룹'과 '같은 그룹'을 찾아 묶는 것을 말합니다.
*
* **영형대용어 분석** 은 문장에서 생략된 기능어를 찾아 문장 내 또는 문장 간에 언급되어 있는 어구와 묶는 분석과정입니다.
*
* 예) '나는 밥을 먹었고, 영희도 먹었다'라는 문장에서,
*
* * '먹었다'의 목적어인 '밥을'이 생략되어 있음을 찾는 것을 말합니다.
*
* 아래를 참고해보세요.
*
* * {@link module:koalanlp/proc.CorefResolver|CorefResolver} 공지시어 해소, 대용어 분석기 interface
* * {@link module:koalanlp/data.Entity#corefGroup|Entity#corefGroup} 해당 개체명이 포함된 개체명 묶음 [CoreferenceGroup]을 반환하는 API
* * {@link module:koalanlp/data.CoreferenceGroup|CoreferenceGroup} 동일한 대상을 지칭하는 개체명을 묶는 API
*
* @return {CoreferenceGroup[]} 공통된 대상을 묶은 [CoreferenceGroup]의 목록. 없다면 빈 리스트.
*/
getCorefGroups() {
return this.corefGroups;
}
/**
* 체언(명사, 수사, 대명사) 및 체언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 체언, 명사형 전성어미 [POS.ETN], 명사 파생 접미사 [POS.XSN]
* - 제외: 관형형 전성어미 [POS.ETM], 동사/형용사/부사 파생 접미사 [POS.XSV], [POS.XSA], [POS.XSM]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @type {Word[]}
*/
get nouns() {
let result = [];
for (const word of this) {
const inclusion = word.findIndex((m) => m.isNoun() || m.hasTagOneOf('ETN', 'XSN'));
const exclusion = word.findLastIndex((m) => m.hasTagOneOf('XSV', 'XSA', 'XSM'));
if (inclusion !== -1 && inclusion > exclusion) {
result.push(word);
}
}
return result;
}
/**
* 체언(명사, 수사, 대명사) 및 체언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 체언, 명사형 전성어미 [POS.ETN], 명사 파생 접미사 [POS.XSN]
* - 제외: 관형형 전성어미 [POS.ETM], 동사/형용사/부사 파생 접미사 [POS.XSV], [POS.XSA], [POS.XSM]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @return {Word[]} 체언 또는 체언 성격의 어휘를 포함하는 어절의 목록
*/
getNouns() {
return this.nouns;
}
/**
* 용언(동사, 형용사) 및 용언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 용언, 동사 파생 접미사 [POS.XSV]
* - 제외: 명사형/관형형 전성어미 [POS.ETN], [POS.ETM], 명사/형용사/부사 파생 접미사 [POS.XSN], [POS.XSA], [POS.XSM]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @type {Word[]}
*/
get verbs() {
let result = [];
for (const word of this) {
const inclusion = word.findIndex((m) => m.isPredicate() || m.tag.equals(POS.XSV));
const exclusion = word.findLastIndex((m) => m.hasTagOneOf('ETN', 'ETM', 'XSN', 'XSA', 'XSM'));
if (inclusion !== -1 && inclusion > exclusion) {
result.push(word);
}
}
return result;
}
/**
* 용언(동사, 형용사) 및 용언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 용언, 동사 파생 접미사 [POS.XSV]
* - 제외: 명사형/관형형 전성어미 [POS.ETN], [POS.ETM], 명사/형용사/부사 파생 접미사 [POS.XSN], [POS.XSA], [POS.XSM]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @return {Word[]} 용언 또는 용언 성격의 어휘를 포함하는 어절의 목록
*/
getVerbs() {
return this.verbs;
}
/**
* 수식언(관형사, 부사) 및 수식언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 수식언, 관형형 전성어미 [POS.ETM], 형용사/부사 파생 접미사 [POS.XSA], [POS.XSM]
* - 제외: 명사형 전성어미 [POS.ETN], 명사/동사 파생 접미사 [POS.XSN], [POS.XSV]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @type {Word[]}
*/
get modifiers() {
let result = [];
for (const word of this) {
const inclusion = word.findIndex((m) => m.isPredicate() || m.hasTagOneOf("ETM", "XSA", "XSM"));
const exclusion = word.findLastIndex((m) => m.hasTagOneOf("ETN", "XSN", "XSV"));
if (inclusion !== -1 && inclusion > exclusion) {
result.push(word);
}
}
return result;
}
/**
* 수식언(관형사, 부사) 및 수식언 성격의 어휘를 포함하는 어절들을 가져옵니다.
*
* - 포함: 수식언, 관형형 전성어미 [POS.ETM], 형용사/부사 파생 접미사 [POS.XSA], [POS.XSM]
* - 제외: 명사형 전성어미 [POS.ETN], 명사/동사 파생 접미사 [POS.XSN], [POS.XSV]
* - 가장 마지막에 적용되는 어미/접미사를 기준으로 판정함
*
* **[참고]**
*
* **전성어미** 는 용언 따위에 붙어 다른 품사의 기능을 수행하도록 변경하는 어미입니다.
* 예) '멋지게 살다'를 '멋지게 삶'으로 바꾸는 명사형 전성어미 '-ㅁ'이 있습니다. 원 기능은 동사이므로 부사의 수식을 받고 있습니다.
*
* **파생접미사** 는 용언의 어근이나 단어 따위에 붙어서 명사로 파생되도록 하는 접미사입니다.
* 예) 역시 '살다'를 '삶'으로 바꾸는 명사파생 접미사 '-ㅁ'이 있습니다. 이 경우 명사이므로 '멋진 삶'과 같이 형용사의 수식을 받습니다.
*
* @return {Word[]} 수식언 또는 수식언 성격의 어휘를 포함하는 어절의 목록
*/
getModifiers() {
return this.modifiers;
}
/**
* 어절의 표면형을 이어붙이되, 지정된 [delimiter]로 띄어쓰기 된 문장을 반환합니다.
* @param {!string} [delimiter=' '] 어절 사이의 띄어쓰기 방식. 기본값 = 공백(" ")
* @return {string} 띄어쓰기 된 문장입니다.
*/
surfaceString(delimiter = ' ') {
return this.map((w) => w.surface).join(delimiter);
}
/**
* 품사분석 결과를, 1행짜리 String으로 변환합니다.
* @return {string} 품사분석 결과를 담은 1행짜리 String.
*/
singleLineString() {
return this.map((w) => w.singleLineString()).join(' ')
}
/**
* @inheritDoc
*/
toString() {
return this.surfaceString();
}
}