Delphi から MeCab(libmecab.dll)を呼び出す

Delphi から libmecab.dll を呼び出すユニット

32bit, 64bit 共用です(生成exeとMeCabで合わせて下さい)
libmecab.dll と辞書ディレクトリのパスをコンストラクタで指定して下さい

呼出ユニット
unit MeCab;

interface

uses
    Winapi.Windows, System.SysUtils, System.Classes;

type
    PMecabTagger = Pointer;
    PMecabNode = Pointer;

    T_mecab_new = function(argc: Integer; argv: PPChar): PMecabTagger; cdecl;
    T_mecab_destroy = procedure(tagger: PMecabTagger); cdecl;
    T_mecab_sparse_tostr = function(tagger: PMecabTagger; str: PAnsiChar): PAnsiChar; cdecl;

    TMeCab = class
    private
        FTagger: PMecabTagger;
        F_mecab_new: T_mecab_new;
        F_mecab_destroy: T_mecab_destroy;
        F_mecab_sparse_tostr: T_mecab_sparse_tostr;

        function LoadDllFunc(DllPath: string): Boolean;
    public
        constructor Create(DllPath: string; Args: array of string); overload;
        constructor Create(DllPath, DicDir: string); overload;
        destructor Destroy; override;

        function Parse(const Text: string): string;
    end;

implementation

function AllocPPChar(StrArray: array of string): PPChar;
begin
    Result := AllocMem(SizeOf(PChar) * Length(StrArray));
{$POINTERMATH ON}
    for var I := Low(StrArray) to High(StrArray) do begin
        Result[I] := PChar(StrArray[I]);
    end;
{$POINTERMATH OFF}
end;

constructor TMeCab.Create(DllPath: string; Args: array of string);
var
    ArgArray: PPChar;
begin
    if (not LoadDllFunc(DllPath)) then begin
        raise Exception.Create('Failed to load DLL.');
    end;

    ArgArray := AllocPPChar(Args);
    try
        FTagger := F_mecab_new(Length(Args), ArgArray);
        if (FTagger = nil) then begin
            raise Exception.Create('Failed to initialize MeCab.');
        end;
    finally
        FreeMem(ArgArray);
    end;
end;

constructor TMeCab.Create(DllPath, DicDir: string);
begin
    Create(DllPath, ['mecab', '-d', DicDir]);
end;

destructor TMeCab.Destroy;
begin
    if Assigned(FTagger) then begin
        F_mecab_destroy(FTagger);
    end;

    inherited;
end;

function TMeCab.LoadDllFunc(DllPath: string): Boolean;
var
    LibHandle: THandle;
begin
    LibHandle := LoadLibrary(PChar(DllPath));
    if (LibHandle <> 0) then begin
        @F_mecab_new := GetProcAddress(LibHandle, 'mecab_new');
        @F_mecab_destroy := GetProcAddress(LibHandle, 'mecab_destroy');
        @F_mecab_sparse_tostr := GetProcAddress(LibHandle, 'mecab_sparse_tostr');

        Result := Assigned(F_mecab_new) and Assigned(F_mecab_destroy) and Assigned(F_mecab_sparse_tostr);
    end else begin
        Result := False;
    end;
end;

function TMeCab.Parse(const Text: string): string;
var
    ResultPtr: PAnsiChar;
    AnsiText: UTF8String;
begin
    if (not Assigned(FTagger)) then begin
        Exit('');
    end;

    AnsiText := UTF8String(Text);
    ResultPtr := F_mecab_sparse_tostr(FTagger, PAnsiChar(AnsiText));
    Result := string(UTF8String(ResultPtr));
end;


end.

使い方
uses MeCab
:
var MeCab: TMeCab;
begin
    MeCab := TMeCab.Create('C:\Program Files\MeCab\bin\libmecab.dll', 'C:\Program Files\MeCab\dic\ipadic');
    try
        dstStr = MeCab.Parse('和布蕪による日本語解析');
    finally
        MeCab.Free;
    end;
end;
※MeCabの改行コードは #10 です

コメント