라이브러리 API
이 장에서는 MeCab-Ko 라이브러리의 주요 API를 설명합니다.
크레이트 구조
mecab-ko (통합 라이브러리)
├── mecab-ko-core (핵심 분석 엔진)
├── mecab-ko-dict (사전 관리)
└── mecab-ko-hangul (한글 유틸리티)
대부분의 경우 mecab-ko 크레이트만 사용하면 됩니다. 개별 기능만 필요한 경우 해당 크레이트를 직접 의존할 수 있습니다.
mecab-ko
Tokenizer
형태소 분석의 메인 인터페이스입니다.
#![allow(unused)] fn main() { use mecab_ko::Tokenizer; }
생성
#![allow(unused)] fn main() { // Create with default dictionary let tokenizer = Tokenizer::new()?; // Create with custom dictionary path let tokenizer = Tokenizer::with_dict("/path/to/dict")?; }
메서드
tokenize(&self, text: &str) -> Vec<Token>
텍스트를 형태소로 분석합니다.
#![allow(unused)] fn main() { let tokens = tokenizer.tokenize("안녕하세요"); for token in tokens { println!("{}: {} ({}-{})", token.surface, token.pos, token.start, token.end); } }
morphs(&self, text: &str) -> Vec<String>
형태소(표면형)만 추출합니다. wakati와 동일합니다.
#![allow(unused)] fn main() { let morphs = tokenizer.morphs("오늘 날씨가 좋습니다"); // ["오늘", "날씨", "가", "좋", "습니다"] }
wakati(&self, text: &str) -> Vec<String>
형태소를 분리하여 표면형 목록으로 반환합니다.
#![allow(unused)] fn main() { let words = tokenizer.wakati("형태소 분석"); // ["형태소", "분석"] }
nouns(&self, text: &str) -> Vec<String>
명사(NN으로 시작하는 품사)만 추출합니다.
#![allow(unused)] fn main() { let nouns = tokenizer.nouns("오늘 날씨가 좋습니다"); // ["오늘", "날씨"] }
pos(&self, text: &str) -> Vec<(String, String)>
(표면형, 품사) 쌍의 목록을 반환합니다.
#![allow(unused)] fn main() { let pos_tagged = tokenizer.pos("안녕하세요"); // [("안녕", "NNG"), ("하", "XSV"), ("세요", "EP+EF")] }
Token
형태소 분석 결과를 나타내는 구조체입니다.
#![allow(unused)] fn main() { pub struct Token { pub surface: String, // 표면형 pub pos: String, // 품사 태그 pub start: usize, // 시작 바이트 위치 pub end: usize, // 끝 바이트 위치 pub reading: Option<String>, // 읽기 pub lemma: Option<String>, // 원형 (기본형) } }
예시:
#![allow(unused)] fn main() { let token = &tokens[0]; println!("Surface: {}", token.surface); println!("POS: {}", token.pos); println!("Position: {}-{}", token.start, token.end); if let Some(reading) = &token.reading { println!("Reading: {}", reading); } }
mecab-ko-hangul
한글 처리를 위한 유틸리티 함수들입니다.
#![allow(unused)] fn main() { use mecab_ko::hangul::*; // or use mecab_ko_hangul::*; }
자모 분리/결합
decompose(c: char) -> Option<(char, char, Option<char>)>
한글 음절을 초성, 중성, 종성으로 분해합니다.
#![allow(unused)] fn main() { let result = decompose('한'); assert_eq!(result, Some(('ㅎ', 'ㅏ', Some('ㄴ')))); let result = decompose('가'); assert_eq!(result, Some(('ㄱ', 'ㅏ', None))); let result = decompose('a'); assert_eq!(result, None); // Not a Hangul syllable }
compose(cho: char, jung: char, jong: Option<char>) -> Option<char>
초성, 중성, 종성을 결합하여 한글 음절을 만듭니다.
#![allow(unused)] fn main() { let c = compose('ㅎ', 'ㅏ', Some('ㄴ')); assert_eq!(c, Some('한')); let c = compose('ㄱ', 'ㅏ', None); assert_eq!(c, Some('가')); }
decompose_str(s: &str) -> String
문자열의 모든 한글 음절을 자모로 분해합니다.
#![allow(unused)] fn main() { let result = decompose_str("한글"); assert_eq!(result, "ㅎㅏㄴㄱㅡㄹ"); let result = decompose_str("Hello 한글"); assert_eq!(result, "Hello ㅎㅏㄴㄱㅡㄹ"); }
compose_str(s: &str) -> String
자모 문자열을 한글 음절로 결합합니다.
#![allow(unused)] fn main() { let result = compose_str("ㅎㅏㄴㄱㅡㄹ"); assert_eq!(result, "한글"); }
문자 판별
is_hangul(c: char) -> bool
한글(음절 또는 자모)인지 확인합니다.
#![allow(unused)] fn main() { assert!(is_hangul('가')); assert!(is_hangul('ㄱ')); assert!(is_hangul('ㅏ')); assert!(!is_hangul('a')); }
is_hangul_syllable(c: char) -> bool
완성형 한글 음절인지 확인합니다.
#![allow(unused)] fn main() { assert!(is_hangul_syllable('가')); assert!(is_hangul_syllable('힣')); assert!(!is_hangul_syllable('ㄱ')); // Jamo, not syllable }
is_jamo(c: char) -> bool
한글 자모인지 확인합니다.
#![allow(unused)] fn main() { assert!(is_jamo('ㄱ')); assert!(is_jamo('ㅏ')); assert!(!is_jamo('가')); // Syllable, not jamo }
is_choseong(c: char) -> bool
초성 자모인지 확인합니다.
#![allow(unused)] fn main() { assert!(is_choseong('ㄱ')); assert!(is_choseong('ㅎ')); assert!(!is_choseong('ㅏ')); // Jungseong, not choseong }
is_jungseong(c: char) -> bool
중성 자모인지 확인합니다.
#![allow(unused)] fn main() { assert!(is_jungseong('ㅏ')); assert!(is_jungseong('ㅣ')); assert!(!is_jungseong('ㄱ')); }
has_jongseong(c: char) -> Option<bool>
한글 음절에 종성이 있는지 확인합니다.
#![allow(unused)] fn main() { assert_eq!(has_jongseong('한'), Some(true)); assert_eq!(has_jongseong('하'), Some(false)); assert_eq!(has_jongseong('a'), None); // Not Hangul }
문자 분류
classify_char(c: char) -> CharType
문자의 종류를 판별합니다.
#![allow(unused)] fn main() { use mecab_ko::CharType; assert_eq!(classify_char('한'), CharType::HangulSyllable); assert_eq!(classify_char('ㄱ'), CharType::HangulJamo); assert_eq!(classify_char('韓'), CharType::Hanja); assert_eq!(classify_char('ア'), CharType::Katakana); assert_eq!(classify_char('あ'), CharType::Hiragana); assert_eq!(classify_char('a'), CharType::Alphabet); assert_eq!(classify_char('1'), CharType::Digit); assert_eq!(classify_char(' '), CharType::Whitespace); assert_eq!(classify_char('.'), CharType::Punctuation); }
CharType 열거형
#![allow(unused)] fn main() { pub enum CharType { HangulSyllable, // 한글 음절 HangulJamo, // 한글 자모 Hanja, // 한자 Katakana, // 가타카나 Hiragana, // 히라가나 Alphabet, // ASCII 알파벳 Digit, // 숫자 Whitespace, // 공백 문자 Punctuation, // 구두점 Other, // 기타 } }
mecab-ko-dict
사전 관리 기능을 제공합니다.
#![allow(unused)] fn main() { use mecab_ko::dict::*; // or use mecab_ko_dict::*; }
UserDictionary
사용자 정의 사전을 관리합니다.
생성 및 엔트리 추가
#![allow(unused)] fn main() { use mecab_ko_dict::UserDictionary; let mut dict = UserDictionary::new(); // Add entry with surface, POS, cost, and optional reading dict.add_entry("딥러닝", "NNG", Some(-1000), None); dict.add_entry("챗GPT", "NNP", Some(-1000), Some("챗지피티".to_string())); }
CSV 파일 로드
#![allow(unused)] fn main() { dict.load_from_csv("user.csv")?; }
CSV 포맷:
# Comment line (starts with #)
표면형,품사,비용,읽기
딥러닝,NNG,-1000,딥러닝
챗GPT,NNP,-1000,챗지피티
CSV 문자열 로드
#![allow(unused)] fn main() { let csv_content = r#" 딥러닝,NNG,-1000, 머신러닝,NNG,-1000, "#; dict.load_from_str(csv_content)?; }
엔트리 조회
#![allow(unused)] fn main() { let entries = dict.lookup("딥러닝"); for entry in entries { println!("{}: {} (cost: {})", entry.surface, entry.pos, entry.cost); } }
기타 메서드
#![allow(unused)] fn main() { // Number of entries let count = dict.len(); // Check if empty let is_empty = dict.is_empty(); // Clear all entries dict.clear(); // Save to CSV file dict.save_to_csv("output.csv")?; // Get all entries let all_entries = dict.entries(); }
UserDictionaryBuilder
빌더 패턴으로 사용자 사전을 생성합니다.
#![allow(unused)] fn main() { use mecab_ko_dict::UserDictionaryBuilder; let dict = UserDictionaryBuilder::new() .default_cost(-500) .add("딥러닝", "NNG") .add_with_cost("머신러닝", "NNG", -300) .add_full("자연어처리", "NNG", -400, Some("자연어처리")) .load_csv("extra.csv")? .build(); }
Entry
사전 엔트리를 나타내는 구조체입니다.
#![allow(unused)] fn main() { pub struct Entry { pub surface: String, // 표면형 pub left_id: u16, // 좌문맥 ID pub right_id: u16, // 우문맥 ID pub cost: i16, // 비용 (낮을수록 우선) pub feature: String, // 품사 정보 } }
UserEntry
사용자 사전 엔트리입니다.
#![allow(unused)] fn main() { pub struct UserEntry { pub surface: String, // 표면형 pub left_id: u16, // 좌문맥 ID pub right_id: u16, // 우문맥 ID pub cost: i16, // 비용 pub pos: String, // 품사 태그 pub reading: Option<String>, // 읽기 pub lemma: Option<String>, // 원형 } }
에러 처리
mecab-ko-core 에러
#![allow(unused)] fn main() { use mecab_ko::Error; match tokenizer.new() { Ok(t) => { /* use tokenizer */ } Err(Error::Dict(e)) => eprintln!("Dictionary error: {}", e), Err(Error::Init(msg)) => eprintln!("Init error: {}", msg), Err(e) => eprintln!("Error: {}", e), } }
mecab-ko-dict 에러
#![allow(unused)] fn main() { use mecab_ko_dict::error::DictError; match dict.load_from_csv("user.csv") { Ok(_) => println!("Loaded successfully"), Err(DictError::Io(e)) => eprintln!("IO error: {}", e), Err(DictError::Format(msg)) => eprintln!("Format error: {}", msg), Err(DictError::Version { expected, found }) => { eprintln!("Version mismatch: expected {}, found {}", expected, found); } } }
전체 예시
use mecab_ko::{Tokenizer, hangul}; use mecab_ko_dict::UserDictionary; fn main() -> Result<(), Box<dyn std::error::Error>> { // Create tokenizer let tokenizer = Tokenizer::new()?; // Basic tokenization let text = "오늘 날씨가 좋습니다"; let tokens = tokenizer.tokenize(text); println!("=== Tokens ==="); for token in &tokens { println!("{}\t{}\t[{},{})", token.surface, token.pos, token.start, token.end); } // Extract nouns println!("\n=== Nouns ==="); let nouns = tokenizer.nouns(text); println!("{:?}", nouns); // Hangul utilities println!("\n=== Hangul ==="); let (cho, jung, jong) = hangul::decompose('한').unwrap(); println!("'한' = {} + {} + {:?}", cho, jung, jong); println!("Decomposed '한글': {}", hangul::decompose_str("한글")); // User dictionary println!("\n=== User Dictionary ==="); let mut dict = UserDictionary::new(); dict.add_entry("딥러닝", "NNG", Some(-1000), None); let entries = dict.lookup("딥러닝"); for entry in entries { println!("{}: {} (cost: {})", entry.surface, entry.pos, entry.cost); } Ok(()) }
추가 문서
자세한 API 문서는 docs.rs에서 확인할 수 있습니다.