루아와 MeCab-ko를 이용한 한국어 형태소 분석

류광, 2019/08/10 19:03
Windows에서 루아로 한국어 형태소 분석을 수행하기 위한 MeCab-ko 루아 바인딩 모듈 만들기와 기타 설정 방법.

Windows에서 루아로 한국어 형태소 분석을 해보자는 생각으로 가장 덜 번거로운 길을 찾아보았습니다.

제가 찾은 답은 다음과 같습니다.

lua-mecab 모듈을 빌드하되, 원래의 MeCab 대신 MeCab-ko의 라이브러리 파일을 링크한다.

lua-mecab 모듈은 C++로 구현된 MeCab의 주요 객체와 함수에 대한 루아 바인딩으로, 이를테면 다음과 같이 사용합니다.1

mecab = require "mecab" -- if you build it yourself, use the .so name (lua-mecab) here
parser = mecab:new("") -- you can pass mecab config options here, like "-Owakati"

print(parser:parse("吾輩は猫である"))

lua-mecab은 cpp 파일 하나로 된 상당히 간단한 모듈이며, 루아의 헤더들과 라이브러리 파일, MeCab의 헤더들과 라이브러리 파일에만 의존합니다.

예제에 일본어 예문이 쓰인 것은 MeCab이 원래 일본어 텍스트를 위해 만들어진 것이기 때문인데요. 한국의 훌륭한 개발자분들이 MeCab을 한국어에 맞게 고쳐서 공개했습니다. MeCab-ko가 바로 그것인데, 문서화에 따르면2

"최소한의 변경으로 한국어의 특성에 맞는 기능을 추가하는 것이 목표"

라고 합니다.

MeCab과 MeCab-ko 둘 다 소스 코드가 *nix 환경을 기준으로 합니다. 다행히 또 다른 훌륭한 개발자분이 MeCab-ko를 MS의 개발 도구로 빌드하기 편하게 만들어 주셨습니다. mecab-ko-msvc 프로젝트가 바로 그것입니다. 게다가 아예 미리 빌드한 이진 파일들도 제공합니다.

MeCab-ko는 MeCab의 기존 API를 최대한 따르기 때문에, lua-mecab을 빌드할 때 MeCab의 라이브러리 대신 MeCab-ko의 라이브러리를 링크해도 오류가 생기지 않습니다.따라서, Visual Studio에서 lua-mecab의 .cpp 파일 하나를 컴파일하고 루아 구현의 라이브러리 파일과 언급한 MeCab-ko 라이브러리 파일(libmecab.lib)을 링크하기만 하면 루아에서 MeCab-ko의 함수를 호출할 수 있는 확장 모듈 DLL 파일이 생깁니다. 이 글에 관심을 가지는 분이라면 아마 VS에서 의존성 두 개 짜리 DLL 프로젝트를 설정하고 빌드하는 데 별 어려움이 없을 것이므로 자세한 방법은 생략하겠습니다. 아주 간단하게는, 관련 파일들을 모두 한 디렉터리에 넣고 모듈 .cpp 소스 코드 자체에서 #pragma comment lib(...)으로 필요한 라이브러리들을 지정하면 될 것입니다. 그러면 프로젝트 속성에서 각종 경로와 추가 lib 파일을 설정할 필요도 없습니다.

여기까지가 기본적인 전략이고, 몇 가지 실천 세부 사항을 살펴보자면: 우선 lua-mecab 소스 코드에는 Windows DLL을 위한 배려가 빠져 있습니다. lua-mecab.cpp 파일 끝부분을 보면 다음과 같은 코드가 있는데,3

extern "C" int luaopen_mecab(lua_State *L)
{
... 중략 ...

}

Windows에서 루아가 모듈을 적재하는 과정에서 이 DLL 함수에 접근할 수 있으려면 다음처럼 이것이 외부로 공개된 DLL 함수임을 명시적으로 표시해 주어야 합니다(적어도 Microsoft VS에서는).

extern "C" __declspec(dllexport) int luaopen_mecab(lua_State *L)
{
... 중략 ...

}

그리고 이런 식으로 얻은 lua-mecab DLL을 바로 루아에서 사용할 수는 없습니다. 몇 가지 준비 작업이 필요한데요.

먼저, lua-mecab에 링크한 MeCab-ko 라이브러리 파일은 실제 코드를 담고 있는 것이 아니라 MeCab-ko 자체의 DLL 파일인 libmecab.dll에 대한 링크 정보만 담고 있습니다. 따라서 그 libmecab.dll(MeCab-ko-msvs의 이진 파일 모음에 포함되어 있습니다)을 호스트 실행 파일(루아를 독립적으로 사용한다면 lua5.x.exe)이 있는 디렉터리 또는 시스템 환경 변수 PATH에 등록된 디렉터리에 복사해야 합니다.

또한 lua-mecab 모듈 DLL 파일 자체도 호스트가 접근할 수 있는 곳에 배치해야 하고요. LuaBinaries 기준으로는 루아 exe 파일(lua5.1.exe 등)이 있는 디렉터리 또는 그 디렉터리의 clib 디렉터리에 넣으면 됩니다.

그리고 MeCab-ko는 형태소 분석을 위해 설정 파일과 외부 사전 파일을 참조합니다. 사전 파일들은 MeCab-ko-dic라는 개별 프로젝트에서 관리하는데, MeCab-ko-msvc 프로젝트를 만든 윤원섭 님이 MeCab-ko-dic의 MSVC 버전과 이진 파일들도 제공합니다. 해당 GitHub 저장소는 https://github.com/Pusnow/mecab-ko-dic-msvc입니다.

MeCab-ko-msvc의 미리 빌드된 실행 파일과 DLL은 설정 파일이 c:\mecab\mecabrc라고 가정합니다. 그리고 사전 파일들을 찾을 폴더는 mecabrc 설정 파일 안에 지정되어 있는데, 기본은 c:\mecab\mecab-ko-dic\입니다. 설정 파일과 사전 파일들을 딱 이대로 배치했다면, 루아에서

mecab = require "mecab"
parser = mecab:new("")

print(parser:parse("아버지가방에들어가신다"))

를 실행해서

아버지 NNG,*,F,아버지,*,*,*,*
가   JKS,*,F,가,*,*,*,*
방   NNG,장소,T,방,*,*,*,*
에   JKB,*,F,에,*,*,*,*
들어가 VV,*,F,들어가,*,*,*,*
신다  EP+EC,*,F,신다,Inflect,EP,EC,시/EP/*+ㄴ다/EC/*
EOS

라는 결과를 얻을 수 있습니다. 띄어쓰기를 하지 않았는데도 '가방'을 하나의 명사로 인식하지 않고 '가'를 조사로, '방'을 명사로 인식했네요. 똑똑합니다.

만일 설정 파일과 사전 파일들을 다른 곳에 두었다면, mecab:new()를 호출할 때 다음처럼 MeCab 설정 파일의 위치를 명시적으로 지정해야 합니다.

parser = mecab:new([[-r C:\설정파일이\있는\경로\설정파일이름]])

또한 MeCab 설정 파일에는 dicdir = C:\사전파일들이\있는\디렉터리 형태로 사전 파일 디렉터리의 절대 경로를 지정해야 하고요.


모듈 빌드 과정과 사용 준비 과정을 번호를 착착 붙여서 단계별로 깔끔하게 정리하면 좋겠지만, 시간이 부족해서 일단 필요한 내용만 주절주절 써 보았습니다. 각 단계의 의도와 함정을 염두에 두고 관련 파일들을 실제로 살펴보면 전체적인 과정이 별거 아니라는 점을 아실 겁니다:) 번역서 독자 지원 경험에 비추어 볼 때 단계들을 너무 명시적으로 제시하면 오히려 읽는 이가 수동적으로 되어서 사소한 문제도 스스로 해결하지 못하는 경우가 있다는 변명으로 글을 마무리합니다.

top
트랙백 0 : 의견 # + 0

근황 - 2019-07-20

류광, 2019/07/20 18:50
Natural Language Processing in Action 번역 중, 블록체인 책 교정 마무리.

이번 주에 Blockchain By Example 2차 역자 교정을 마쳤습니다. 큰 문제가 없다면 늦어도 8월 중순에는 책이 나오지 않을까 합니다.

지금 번역하는 책은 매닝 출판사의 Natural Language Processing in Action입니다. 매닝 책(특히 In Action 시리즈) 번역 제안이 몇 번 있었지만 번번이 뭔가가 잘 안 맞아서 무산되었는데요. 이번에 드디어 매닝 책을 하게 되었습니다:) 게다가 전부터 관심이 있었던 자연어 처리 분야의 책이라서 더욱더 기쁩니다.

한국어로 된 NLP 책이라면 당연히 "한국어 처리에 관한 내용은 있는가?"라는 질문이 제기될 텐데요. 요즘의 심층 학습(딥 러닝) 기반 NLP는 예전의 NLP(정규 표현식 기반)에 비해 훨씬 더 언어 중립적이라고 하지만, 그래도 애초에 영어권 저자가 영어를 기준으로 쓴 책이니 한국어 관련 내용은 제한적일 수밖에 없습니다. 안타깝게도 본문과 예제 코드를 한국어에 맞게 수정하는 것은 제가 할 수 있는/해도 되는 범위 밖의 일이고요. 본문을 충실하게 옮기는 데 주력하되, 역주로라도 한국어 처리 관련 정보를 최대한 추가할 생각입니다.

관련해서 KoNLPy를 살펴보고 있는데 재밌네요. 뭔가 성과가 있으면 번역서 역주는 물론 이 곳 블로그에도 공유하겠습니다.

참, 저번 달에 트위터 계정 하나 새로 만들었습니다: @ryugwang

꽤 오래전부터 @GpgStudy을 근근이 유지해 오고 있긴 한데 기본적으로 GpgStudy.com 소식과 공지를 위한 것이라서, 개인적인 근황이나 단상, 링크를 공유할 계정이 따로 하나 있으면 좋겠다는 생각이 들었습니다.

top
TAG 근황
트랙백 0 : 의견 # + 0

나의 첫 Go 프로그램

류광, 2019/06/01 14:00
Go 언어 몇십 분 정도 공부하고 짜본 프로그램입니다.

역자의 글에서 몇 번 언급한 적이 있지만, 번역하면서 비영어권 인명이나 지명을 만났을 때 한글라이즈라는 서비스를 아주 유용하게 사용하고 있습니다. 이 자리를 빌려 한글라이즈 관계자 분들께 다시금 감사 인사 드립니다.

그런데 한글라이즈 웹 서비스가 가끔 HTTP 503 오류를 뿜을 때가 있었습니다. 아주 가끔이고 시간이 조금 지나면 정상화되어서 한글라이즈 GitHub 저장소에 이슈를 등록하지는 않았는데요. 다음에 같은 일이 벌어지면 문제를 보고할 생각입니다.

비록 짧은 시간이지만 한글라이즈 웹 서비스가 안 될 때를 위해, 한글라이즈의 기능을 명령줄에서 사용할 수 있는 간단한 프로그램을 짜보았습니다.

GitHub 저장소에서 보듯이 현재 버전의 한글라이즈는 Go 언어로 구현되었습니다. Go 언어는 많이 들어 보았지만 공부해 본 적은 없는데, 일단 딱 필요한 만큼만 배워 보자고 생각하고 웹에서 강좌를 찾아보았습니다. 다행히 예제로 배우는 GO 프로그래밍이라는 훌륭한 사이트를 발견하고 한 15분 정도 읽은 후 바로 코딩으로 들어갔습니다(그 사이에 https://golang.org/에서 Go 개발 환경을 설치했고요).

우선 해야 할 일은 한글라이즈 Go 라이브러리를 설치하는 것인데, 다음 명령으로 한 번에 끝나더군요. 아주 인상적이었습니다.

> go get -u github.com/hangulize/hangulize

이 라이브러리의 사용법은 해당 GitHub 저장소의 Readme.md에도 나와있듯이 아주 간단합니다.1

import "github.com/hangulize/hangulize"

hangulize.Hangulize("ita", "Cappuccino")
// output: "카푸치노"

즉, 그냥 언어 코드와 문자열을 지정해서 Hangulize 함수를 호출하면 제가 원했던 결과가 반환됩니다.

전체적인 계획이 섰습니다. 명령줄 인수들로 지정된 언어 코드와 전사할 문자열로 Hangulize 함수를 호출해서 그 결과를 출력하면 끝입니다. 각설하고, 다음이 저의 첫 Go 프로그램입니다.

package main
import "os"
import "github.com/hangulize/hangulize"

func main() {
    var lang = os.Args[1]
    var str = os.Args[2]
    println(hangulize.Hangulize(lang, str))
}

이 코드를 hangulize-cmd.go라는 파일로 저장하고, 다음 명령으로 시험해 보았습니다.

> go run hangulize-cmd.go ita "cappuccino" 

카푸치노

의도대로 작동함을 확인한 후에는 다음 명령으로 실행 파일을 생성했습니다.

> go build -o hangulize.exe hangulize-cmd.go

다음은 위의 프로그램을 조금 개선한 버전입니다.

package main
import (
    "os"
    "strings"
)
import "github.com/hangulize/hangulize"
import "github.com/gojp/kana"

func main() {
    if len(os.Args) < 2 {
        println("Usage:\n\thangulize <lang-code> \"string to transcribe\"\n\n" +
            "See https://github.com/hangulize/hangulize for language codes.")
        return
    }
    var lang = os.Args[1]
    var str = os.Args[2]
    if lang == "jpn" {
        str = kana.RomajiToHiragana(strings.ToLower(str))
    }
    println(hangulize.Hangulize(lang, str))
}

우선 명령줄 인수가 두 개 미만일 때의 처리를 추가했고, 영문자로 표시된 일본어 문구를 적절히 처리하는 기능도 추가했습니다. 한글라이즈는 기본적으로 글자 대 글자 차원의 전사 프로그램인데, 일본어는 한자와 가나 문자만 처리합니다. 그래서 "Tokyo"에서 바로 "도쿄"를 얻을 수는 없고,2 "Tokyo"를 먼저 "とうきょう"로 변환해야 합니다. 다행히 그런 기능을 제공하는 Go 라이브러리(https://github.com/gojp/kana)가 있어서 아주 간단하게 처리할 수 있었습니다.


처음 접한 Go의 인상은 아주 좋습니다. 필요한 만큼 배우고 배운 만큼 써먹을 수 있었고, 원하는 라이브러리도 쉽게 찾아서 적용할 수 있었습니다. 개발 환경을 준비하기도 아주 쉬웠고요.


  1. https://github.com/hangulize/hangulize/blob/master/README.md 

  2. 이것이 한글라이즈의 원래 용도는 아닐 것이고, 수식의 그리스 글자 몇 개 빼고는 거의 로마자로만 이루어진 영어 원서들을 번역하다 보니 생기는 요구입니다. 러시아어도 상황이 비슷한데, 키릴 문자를 영문자로 변환하는 Go 라이브러리를 찾으면 관련 기능을 추가할 생각입니다. 

top
트랙백 0 : 의견 # + 0

'Discovering Statistics Using R' 번역서 '앤디 필드의 유쾌한 R 통계학' 출간 소식 및 근황

류광, 2019/03/23 13:59
앤디 필드의 'Discovering Statistics Using R'를 번역한 '앤디 필드의 유쾌한 R 통계학' 드디어 나왔습니다.

본문 열기

top
트랙백 0 : 의견 # + 0

클라우드플레어와 방문자 IP 주소

류광, 2019/02/04 18:55
GpgStudy에 클라우드플레어를 적용하면서 겪은 문제점과 그 해결책

본문 열기

top
트랙백 0 : 의견 # + 0

◀ PREV : [1] : [2] : [3] : [4] : [5] : [6] : [7] : ... [67] : NEXT ▶