1 module libmecab.common;
2 
3 import bindbc.mecab;
4 
5 shared static this()
6 {
7     const support = loadMeCab();
8     assert(support == MeCabSupport.mecab);
9 }
10 
11 shared static ~this()
12 {
13     unloadMeCab();
14 }
15 
16 struct MeCabModel
17 {
18     private mecab_model_t* handle;
19 
20     @disable this();
21     @disable this(this);
22 
23     package this(mecab_model_t* handle)
24     {
25         this.handle = handle;
26     }
27 
28     ~this()
29     {
30         mecab_model_destroy(this.handle);
31     }
32 
33     MeCabTagger createTagger()
34     {
35         return MeCabTagger(mecab_model_new_tagger(handle));
36     }
37 
38     MeCabLattice createLattice()
39     {
40         return MeCabLattice(mecab_model_new_lattice(handle));
41     }
42 
43     static MeCabModel create()
44     {
45         auto model = mecab_model_new(0, null);
46         return MeCabModel(model);
47     }
48 
49     static MeCabModel create(string arg)
50     {
51         auto buf = new char[arg.length + 1];
52         buf[0 .. $ - 1] = arg[];
53         buf[$ - 1] = 0;
54         auto model = mecab_model_new2(buf.ptr);
55         return MeCabModel(model);
56     }
57 }
58 
59 struct MeCabTagger
60 {
61     private mecab_t* handle;
62 
63     @disable this();
64     @disable this(this);
65 
66     package this(mecab_t* handle)
67     {
68         this.handle = handle;
69     }
70 
71     ~this()
72     {
73         mecab_destroy(handle);
74     }
75 
76     MeCabNodeRange parseToNodes(scope ref MeCabLattice lattice)
77     {
78         mecab_parse_lattice(handle, lattice.handle);
79         return MeCabNodeRange(lattice.bosNode());
80     }
81 
82     MeCabNodeRange parseToNodes(string text)
83     {
84         auto lattice = MeCabLattice.create();
85         lattice.sentence = text;
86         return parseToNodes(lattice);
87     }
88 
89     static MeCabTagger create()
90     {
91         auto handle = mecab_new(0, null);
92         return MeCabTagger(handle);
93     }
94 }
95 
96 struct MeCabLattice
97 {
98     private mecab_lattice_t* handle;
99 
100     @disable this();
101     @disable this(this);
102 
103     package this(mecab_lattice_t* handle)
104     {
105         this.handle = handle;
106     }
107 
108     void sentence(const(char)[] text)
109     {
110         mecab_lattice_set_sentence2(handle, text.ptr, text.length);
111     }
112 
113     package mecab_node_t* bosNode()
114     {
115         return mecab_lattice_get_bos_node(handle);
116     }
117 
118     static MeCabLattice create()
119     {
120         return MeCabLattice(mecab_lattice_new());
121     }
122 }
123 
124 struct MeCabNode
125 {
126     string surface;
127     string feature;
128     uint id;
129     ushort rcAttr;
130     ushort lcAttr;
131     ushort posId;
132     ubyte charType;
133     ubyte stat;
134     ubyte isBest;
135     float alpha;
136     float beta;
137     float prob;
138     long cost;
139     short wcost;
140 }
141 
142 struct MeCabNodeRange
143 {
144     private mecab_node_t* node;
145 
146     @disable this();
147     
148     this(mecab_node_t* node)
149     {
150         this.node = node;
151     }
152 
153     bool empty() const pure nothrow @safe @nogc
154     {
155         return node is null;
156     }
157 
158     auto front() const pure nothrow
159     in(!empty)
160     {
161         import std.conv : to;
162 
163         return MeCabNode(
164             node.surface[0 .. node.length].to!string(),
165             node.feature.to!string(),
166             node.id,
167             node.rcAttr,
168             node.lcAttr,
169             node.posid,
170             node.char_type,
171             node.stat,
172             node.isbest,
173             node.alpha,
174             node.beta,
175             node.prob,
176             node.cost,
177             node.wcost
178         );
179     }
180 
181     void popFront() nothrow @safe @nogc
182     in(!empty)
183     {
184         this.node = this.node.next;
185     }
186 }