ruby-sfst 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1 -0
- data/Manifest +31 -0
- data/README.rdoc +25 -0
- data/Rakefile +22 -0
- data/ext/sfst_machine/alphabet.C +807 -0
- data/ext/sfst_machine/alphabet.h +281 -0
- data/ext/sfst_machine/basic.C +84 -0
- data/ext/sfst_machine/basic.h +24 -0
- data/ext/sfst_machine/compact.C +616 -0
- data/ext/sfst_machine/compact.h +98 -0
- data/ext/sfst_machine/determinise.C +304 -0
- data/ext/sfst_machine/extconf.rb +4 -0
- data/ext/sfst_machine/fst-compiler.C +2375 -0
- data/ext/sfst_machine/fst-compiler.h +113 -0
- data/ext/sfst_machine/fst-compiler.yy +213 -0
- data/ext/sfst_machine/fst.C +966 -0
- data/ext/sfst_machine/fst.h +365 -0
- data/ext/sfst_machine/interface.C +1838 -0
- data/ext/sfst_machine/interface.h +94 -0
- data/ext/sfst_machine/make-compact.C +328 -0
- data/ext/sfst_machine/make-compact.h +34 -0
- data/ext/sfst_machine/mem.h +74 -0
- data/ext/sfst_machine/operators.C +1131 -0
- data/ext/sfst_machine/sfst_machine.cc +411 -0
- data/ext/sfst_machine/utf8-scanner.C +2197 -0
- data/ext/sfst_machine/utf8-scanner.ll +179 -0
- data/ext/sfst_machine/utf8.C +146 -0
- data/ext/sfst_machine/utf8.h +19 -0
- data/lib/sfst.rb +99 -0
- data/ruby-sfst.gemspec +34 -0
- data/test/test_sfst.fst +3 -0
- data/test/test_sfst.rb +119 -0
- metadata +100 -0
@@ -0,0 +1,807 @@
|
|
1
|
+
|
2
|
+
/*******************************************************************/
|
3
|
+
/* */
|
4
|
+
/* FILE alphabet.C */
|
5
|
+
/* MODULE alphabet */
|
6
|
+
/* PROGRAM SFST */
|
7
|
+
/* AUTHOR Helmut Schmid, IMS, University of Stuttgart */
|
8
|
+
/* */
|
9
|
+
/* PURPOSE basic FST functions */
|
10
|
+
/* */
|
11
|
+
/*******************************************************************/
|
12
|
+
|
13
|
+
#include "utf8.h"
|
14
|
+
#include "alphabet.h"
|
15
|
+
|
16
|
+
using std::vector;
|
17
|
+
using std::ostream;
|
18
|
+
using __gnu_cxx::hash_map;
|
19
|
+
using __gnu_cxx::hash_set;
|
20
|
+
|
21
|
+
const int BUFFER_SIZE=100000;
|
22
|
+
|
23
|
+
char EpsilonString[]="<>";
|
24
|
+
|
25
|
+
|
26
|
+
/*******************************************************************/
|
27
|
+
/* */
|
28
|
+
/* Alphabet::add */
|
29
|
+
/* */
|
30
|
+
/*******************************************************************/
|
31
|
+
|
32
|
+
void Alphabet::add( const char *symbol, Character c )
|
33
|
+
|
34
|
+
{
|
35
|
+
char *s = fst_strdup(symbol);
|
36
|
+
cm[c] = s;
|
37
|
+
sm[s] = c;
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
/*******************************************************************/
|
42
|
+
/* */
|
43
|
+
/* Alphabet::Alphabet */
|
44
|
+
/* */
|
45
|
+
/*******************************************************************/
|
46
|
+
|
47
|
+
Alphabet::Alphabet()
|
48
|
+
|
49
|
+
{
|
50
|
+
utf8 = false;
|
51
|
+
add(EpsilonString, Label::epsilon);
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
/*******************************************************************/
|
56
|
+
/* */
|
57
|
+
/* Alphabet::clear */
|
58
|
+
/* */
|
59
|
+
/*******************************************************************/
|
60
|
+
|
61
|
+
void Alphabet::clear()
|
62
|
+
|
63
|
+
{
|
64
|
+
char **s=new char*[cm.size()];
|
65
|
+
ls.clear();
|
66
|
+
sm.clear();
|
67
|
+
|
68
|
+
size_t i, n=0;
|
69
|
+
for( CharMap::iterator it=cm.begin(); it!=cm.end(); it++ )
|
70
|
+
s[n++] = it->second;
|
71
|
+
cm.clear();
|
72
|
+
|
73
|
+
for( i=0; i<n; i++ )
|
74
|
+
free(s[i]);
|
75
|
+
delete[] s;
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
/*******************************************************************/
|
80
|
+
/* */
|
81
|
+
/* Alphabet::new_marker */
|
82
|
+
/* */
|
83
|
+
/*******************************************************************/
|
84
|
+
|
85
|
+
Character Alphabet::new_marker()
|
86
|
+
|
87
|
+
{
|
88
|
+
// find some unused character code
|
89
|
+
for(Character i=1; i!=0; i++)
|
90
|
+
if (cm.find(i) == cm.end()) {
|
91
|
+
// create a unique identifier string
|
92
|
+
char symbol[100];
|
93
|
+
sprintf(symbol,">%ld<",(long)i);
|
94
|
+
add(symbol, i);
|
95
|
+
return i;
|
96
|
+
}
|
97
|
+
|
98
|
+
throw "Error: too many symbols in transducer definition";
|
99
|
+
}
|
100
|
+
|
101
|
+
|
102
|
+
/*******************************************************************/
|
103
|
+
/* */
|
104
|
+
/* is_marker_symbol */
|
105
|
+
/* */
|
106
|
+
/*******************************************************************/
|
107
|
+
|
108
|
+
static bool is_marker_symbol( const char *s )
|
109
|
+
|
110
|
+
{
|
111
|
+
// recogize strings matching the expression ">[0-9]+<"
|
112
|
+
if (s != NULL && *s == '>') {
|
113
|
+
do { s++; } while (*s >= '0' && *s <= '9');
|
114
|
+
if (*s=='<' && *(s+1) == 0 && *(s-1) != '>')
|
115
|
+
return true;
|
116
|
+
}
|
117
|
+
return false;
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
/*******************************************************************/
|
122
|
+
/* */
|
123
|
+
/* Alphabet::delete_markers */
|
124
|
+
/* */
|
125
|
+
/*******************************************************************/
|
126
|
+
|
127
|
+
void Alphabet::delete_markers()
|
128
|
+
|
129
|
+
{
|
130
|
+
vector<char*> sym;
|
131
|
+
vector<Character> code;
|
132
|
+
vector<Label> label;
|
133
|
+
|
134
|
+
for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
|
135
|
+
Character c=it->first;
|
136
|
+
char *s=it->second;
|
137
|
+
if (!is_marker_symbol(s)) {
|
138
|
+
sym.push_back(fst_strdup(s));
|
139
|
+
code.push_back(c);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
for( LabelSet::const_iterator it=begin(); it!=end(); it++ ) {
|
144
|
+
Label l=*it;
|
145
|
+
if (!is_marker_symbol(code2symbol(l.upper_char())) &&
|
146
|
+
!is_marker_symbol(code2symbol(l.lower_char())))
|
147
|
+
label.push_back(l);
|
148
|
+
}
|
149
|
+
|
150
|
+
clear();
|
151
|
+
|
152
|
+
for( size_t i=0; i<sym.size(); i++ ) {
|
153
|
+
add_symbol(sym[i], code[i]);
|
154
|
+
free(sym[i]);
|
155
|
+
}
|
156
|
+
for( size_t i=0; i<label.size(); i++ )
|
157
|
+
insert( label[i] );
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
/*******************************************************************/
|
162
|
+
/* */
|
163
|
+
/* Alphabet::add_symbol */
|
164
|
+
/* */
|
165
|
+
/*******************************************************************/
|
166
|
+
|
167
|
+
Character Alphabet::add_symbol(const char *symbol)
|
168
|
+
|
169
|
+
{
|
170
|
+
if (sm.find(symbol) != sm.end())
|
171
|
+
return sm[symbol];
|
172
|
+
|
173
|
+
// assign the symbol to some unused character
|
174
|
+
for(Character i=1; i!=0; i++)
|
175
|
+
if (cm.find(i) == cm.end()) {
|
176
|
+
add(symbol, i);
|
177
|
+
return i;
|
178
|
+
}
|
179
|
+
|
180
|
+
throw "Error: too many symbols in transducer definition";
|
181
|
+
}
|
182
|
+
|
183
|
+
|
184
|
+
/*******************************************************************/
|
185
|
+
/* */
|
186
|
+
/* Alphabet::add_symbol */
|
187
|
+
/* */
|
188
|
+
/*******************************************************************/
|
189
|
+
|
190
|
+
void Alphabet::add_symbol( const char *symbol, Character c )
|
191
|
+
|
192
|
+
{
|
193
|
+
// check whether the symbol was previously defined
|
194
|
+
int sc=symbol2code(symbol);
|
195
|
+
if (sc != EOF) {
|
196
|
+
if ((Character)sc == c)
|
197
|
+
return;
|
198
|
+
|
199
|
+
if (strlen(symbol) < 60) {
|
200
|
+
static char message[100];
|
201
|
+
sprintf(message, "Error: reinserting symbol '%s' in alphabet with incompatible character value %u %u", symbol, (unsigned)sc, (unsigned)c);
|
202
|
+
throw message;
|
203
|
+
}
|
204
|
+
else
|
205
|
+
throw "reinserting symbol in alphabet with incompatible character value";
|
206
|
+
}
|
207
|
+
|
208
|
+
// check whether the character is already in use
|
209
|
+
const char *s=code2symbol(c);
|
210
|
+
if (s == NULL)
|
211
|
+
add(symbol, c);
|
212
|
+
else {
|
213
|
+
if (strcmp(s, symbol) != 0) {
|
214
|
+
static char message[100];
|
215
|
+
if (strlen(symbol) < 70)
|
216
|
+
sprintf(message,"Error: defining symbol %s as character %d (previously defined as %s)", symbol, (unsigned)c, s);
|
217
|
+
else
|
218
|
+
sprintf(message,"Error: defining a (very long) symbol with previously used character");
|
219
|
+
throw message;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
/*******************************************************************/
|
226
|
+
/* */
|
227
|
+
/* Alphabet::write_char */
|
228
|
+
/* */
|
229
|
+
/*******************************************************************/
|
230
|
+
|
231
|
+
void Alphabet::write_char( Character c, char *buffer, int *pos,
|
232
|
+
bool with_brackets) const
|
233
|
+
{
|
234
|
+
const char *s = code2symbol(c);
|
235
|
+
|
236
|
+
if (s) {
|
237
|
+
int i = 0;
|
238
|
+
int l=strlen(s)-1;
|
239
|
+
if (!with_brackets && s[i] == '<' && s[l] == '>') { i++; l--; }
|
240
|
+
while (i <= l)
|
241
|
+
buffer[(*pos)++] = s[i++];
|
242
|
+
}
|
243
|
+
else {
|
244
|
+
unsigned int uc = c;
|
245
|
+
if (uc>=32 && uc<256)
|
246
|
+
buffer[(*pos)++] = (char)c;
|
247
|
+
else {
|
248
|
+
sprintf(buffer+(*pos),"\\%u", uc);
|
249
|
+
*pos += strlen(buffer+(*pos));
|
250
|
+
}
|
251
|
+
}
|
252
|
+
buffer[*pos] = '\0';
|
253
|
+
}
|
254
|
+
|
255
|
+
|
256
|
+
/*******************************************************************/
|
257
|
+
/* */
|
258
|
+
/* Alphabet::write_char */
|
259
|
+
/* */
|
260
|
+
/*******************************************************************/
|
261
|
+
|
262
|
+
const char *Alphabet::write_char( Character c, bool with_brackets ) const
|
263
|
+
|
264
|
+
{
|
265
|
+
static char buffer[1000];
|
266
|
+
int n=0;
|
267
|
+
|
268
|
+
write_char( c, buffer, &n, with_brackets );
|
269
|
+
return buffer;
|
270
|
+
}
|
271
|
+
|
272
|
+
|
273
|
+
/*******************************************************************/
|
274
|
+
/* */
|
275
|
+
/* Alphabet::write_label */
|
276
|
+
/* */
|
277
|
+
/*******************************************************************/
|
278
|
+
|
279
|
+
void Alphabet::write_label( Label l, char *buffer, int *pos,
|
280
|
+
bool with_brackets ) const
|
281
|
+
{
|
282
|
+
Character lc=l.lower_char();
|
283
|
+
Character uc=l.upper_char();
|
284
|
+
write_char( lc, buffer, pos, with_brackets );
|
285
|
+
if (lc != uc) {
|
286
|
+
buffer[(*pos)++] = ':';
|
287
|
+
write_char( uc, buffer, pos, with_brackets );
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
|
292
|
+
/*******************************************************************/
|
293
|
+
/* */
|
294
|
+
/* Alphabet::write_label */
|
295
|
+
/* */
|
296
|
+
/*******************************************************************/
|
297
|
+
|
298
|
+
const char *Alphabet::write_label( Label l, bool with_brackets ) const
|
299
|
+
|
300
|
+
{
|
301
|
+
static char buffer[1000];
|
302
|
+
int n=0;
|
303
|
+
write_label( l, buffer, &n, with_brackets );
|
304
|
+
return buffer;
|
305
|
+
}
|
306
|
+
|
307
|
+
|
308
|
+
/*******************************************************************/
|
309
|
+
/* */
|
310
|
+
/* Alphabet::insert_symbols */
|
311
|
+
/* */
|
312
|
+
/*******************************************************************/
|
313
|
+
|
314
|
+
void Alphabet::insert_symbols( const Alphabet &a )
|
315
|
+
|
316
|
+
{
|
317
|
+
for( CharMap::const_iterator it=a.cm.begin(); it!=a.cm.end(); it++ )
|
318
|
+
add_symbol(it->second, it->first);
|
319
|
+
}
|
320
|
+
|
321
|
+
|
322
|
+
/*******************************************************************/
|
323
|
+
/* */
|
324
|
+
/* Alphabet::complement */
|
325
|
+
/* */
|
326
|
+
/*******************************************************************/
|
327
|
+
|
328
|
+
void Alphabet::complement( vector<Character> &sym )
|
329
|
+
|
330
|
+
{
|
331
|
+
vector<Character> result;
|
332
|
+
for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
|
333
|
+
Character c = it->first;
|
334
|
+
if (c != Label::epsilon) {
|
335
|
+
size_t i;
|
336
|
+
for( i=0; i<sym.size(); i++ )
|
337
|
+
if (sym[i] == c)
|
338
|
+
break;
|
339
|
+
if (i == sym.size())
|
340
|
+
result.push_back(c);
|
341
|
+
}
|
342
|
+
}
|
343
|
+
sym.swap(result);
|
344
|
+
}
|
345
|
+
|
346
|
+
|
347
|
+
/*******************************************************************/
|
348
|
+
/* */
|
349
|
+
/* Alphabet::copy */
|
350
|
+
/* */
|
351
|
+
/*******************************************************************/
|
352
|
+
|
353
|
+
void Alphabet::copy( const Alphabet &a )
|
354
|
+
|
355
|
+
{
|
356
|
+
insert_symbols( a );
|
357
|
+
utf8 = a.utf8;
|
358
|
+
for( LabelSet::const_iterator it=a.begin(); it!=a.end(); it++ )
|
359
|
+
ls.insert( *it );
|
360
|
+
}
|
361
|
+
|
362
|
+
|
363
|
+
/*******************************************************************/
|
364
|
+
/* */
|
365
|
+
/* Alphabet::compose */
|
366
|
+
/* */
|
367
|
+
/*******************************************************************/
|
368
|
+
|
369
|
+
void Alphabet::compose( const Alphabet &la, const Alphabet &ua )
|
370
|
+
|
371
|
+
{
|
372
|
+
// insert the symbols
|
373
|
+
insert_symbols(la);
|
374
|
+
insert_symbols(ua);
|
375
|
+
utf8 = la.utf8;
|
376
|
+
|
377
|
+
hash_map<Character, hash_set<Character> > cs;
|
378
|
+
|
379
|
+
// create a hash table for a quick lookup of the target characters
|
380
|
+
for( iterator it=ua.begin(); it!=ua.end(); it++ ) {
|
381
|
+
Character lc=it->lower_char();
|
382
|
+
if (lc == Label::epsilon)
|
383
|
+
insert(*it);
|
384
|
+
else
|
385
|
+
cs[lc].insert(it->upper_char());
|
386
|
+
}
|
387
|
+
|
388
|
+
for( iterator it=la.begin(); it!=la.end(); it++ ) {
|
389
|
+
Character uc=it->upper_char();
|
390
|
+
if (uc == Label::epsilon)
|
391
|
+
insert(*it);
|
392
|
+
else {
|
393
|
+
if (cs.find(uc) != cs.end()) {
|
394
|
+
hash_set<Character> s=cs[uc];
|
395
|
+
Character lc=it->lower_char();
|
396
|
+
for( hash_set<Character>::iterator it=s.begin(); it!=s.end(); it++)
|
397
|
+
insert(Label(lc, *it));
|
398
|
+
}
|
399
|
+
}
|
400
|
+
}
|
401
|
+
}
|
402
|
+
|
403
|
+
|
404
|
+
/*******************************************************************/
|
405
|
+
/* */
|
406
|
+
/* operator<<(Alphabet) */
|
407
|
+
/* */
|
408
|
+
/*******************************************************************/
|
409
|
+
|
410
|
+
ostream &operator<<( ostream &s, const Alphabet &a )
|
411
|
+
|
412
|
+
{
|
413
|
+
for( Alphabet::CharMap::const_iterator it=a.cm.begin(); it!=a.cm.end(); it++ )
|
414
|
+
s << it->first << " -> " << it->second << "\n";
|
415
|
+
for( Alphabet::iterator it=a.begin(); it!=a.end(); it++ )
|
416
|
+
s << a.write_label(*it) << " ";
|
417
|
+
s << "\n";
|
418
|
+
return s;
|
419
|
+
}
|
420
|
+
|
421
|
+
|
422
|
+
/*******************************************************************/
|
423
|
+
/* */
|
424
|
+
/* Alphabet::next_mcsym */
|
425
|
+
/* */
|
426
|
+
/* recognizes multi-character symbols which are enclosed with */
|
427
|
+
/* angle brackets <...>. If the value of the argument flag is */
|
428
|
+
/* smaller than 2, the multi-character symbol must be already in */
|
429
|
+
/* the lexicon in order to be recognized. */
|
430
|
+
/* */
|
431
|
+
/*******************************************************************/
|
432
|
+
|
433
|
+
int Alphabet::next_mcsym( char* &string, int extended )
|
434
|
+
|
435
|
+
{
|
436
|
+
char *start=string;
|
437
|
+
|
438
|
+
if (*start == '<')
|
439
|
+
// symbol might start here
|
440
|
+
for( char *end=start+1; *end; end++ )
|
441
|
+
if (*end == '>') {
|
442
|
+
// matching pair of angle brackets found
|
443
|
+
// mark the end of the substring with \0
|
444
|
+
char lastc = *(++end);
|
445
|
+
*end = 0;
|
446
|
+
|
447
|
+
int c;
|
448
|
+
if (extended <= 2)
|
449
|
+
c = add_symbol( start );
|
450
|
+
else
|
451
|
+
c = symbol2code(start);
|
452
|
+
// restore the original string
|
453
|
+
*end = lastc;
|
454
|
+
|
455
|
+
if (c != EOF) {
|
456
|
+
// symbol found
|
457
|
+
// return its code
|
458
|
+
string = end;
|
459
|
+
return (Character)c;
|
460
|
+
}
|
461
|
+
else
|
462
|
+
// not a complex character
|
463
|
+
break;
|
464
|
+
}
|
465
|
+
return EOF;
|
466
|
+
}
|
467
|
+
|
468
|
+
|
469
|
+
/*******************************************************************/
|
470
|
+
/* */
|
471
|
+
/* Alphabet::next_code */
|
472
|
+
/* */
|
473
|
+
/*******************************************************************/
|
474
|
+
|
475
|
+
int Alphabet::next_code( char* &string, int extended )
|
476
|
+
|
477
|
+
{
|
478
|
+
if (*string == 0)
|
479
|
+
return EOF; // finished
|
480
|
+
|
481
|
+
int c = next_mcsym(string, extended);
|
482
|
+
if (c != EOF)
|
483
|
+
return c;
|
484
|
+
|
485
|
+
if (extended && *string == '\\')
|
486
|
+
string++; // remove quotation
|
487
|
+
|
488
|
+
if (utf8) {
|
489
|
+
unsigned int c = utf8toint( &string );
|
490
|
+
return (int)add_symbol(int2utf8(c));
|
491
|
+
}
|
492
|
+
else {
|
493
|
+
char buffer[2];
|
494
|
+
buffer[0] = *string;
|
495
|
+
buffer[1] = 0;
|
496
|
+
string++;
|
497
|
+
return (int)add_symbol(buffer);
|
498
|
+
}
|
499
|
+
}
|
500
|
+
|
501
|
+
|
502
|
+
/*******************************************************************/
|
503
|
+
/* */
|
504
|
+
/* Alphabet::next_label */
|
505
|
+
/* */
|
506
|
+
/*******************************************************************/
|
507
|
+
|
508
|
+
Label Alphabet::next_label( char* &string, int extended )
|
509
|
+
|
510
|
+
{
|
511
|
+
// read first character
|
512
|
+
int c = next_code( string, extended );
|
513
|
+
if (c == EOF)
|
514
|
+
return Label(); // end of string reached
|
515
|
+
|
516
|
+
Character lc=(Character)c;
|
517
|
+
if (!extended || *string != ':') { // single character?
|
518
|
+
if (lc == Label::epsilon)
|
519
|
+
return next_label(string); // ignore epsilon
|
520
|
+
return Label(lc);
|
521
|
+
}
|
522
|
+
|
523
|
+
// read second character
|
524
|
+
string++; // jump over ':'
|
525
|
+
c = next_code( string );
|
526
|
+
if (c == EOF) {
|
527
|
+
static char buffer[1000];
|
528
|
+
sprintf(buffer,"Error: incomplete symbol in input file: %s", string);
|
529
|
+
throw buffer;
|
530
|
+
}
|
531
|
+
|
532
|
+
Label l(lc, (Character)c);
|
533
|
+
if (l.is_epsilon())
|
534
|
+
return next_label(string); // ignore epsilon transitions
|
535
|
+
return l;
|
536
|
+
}
|
537
|
+
|
538
|
+
|
539
|
+
/*******************************************************************/
|
540
|
+
/* */
|
541
|
+
/* Alphabet::string2symseq */
|
542
|
+
/* */
|
543
|
+
/*******************************************************************/
|
544
|
+
|
545
|
+
void Alphabet::string2symseq( char *s, vector<Character> &ch )
|
546
|
+
|
547
|
+
{
|
548
|
+
int c;
|
549
|
+
while ((c = next_code(s, false)) != EOF)
|
550
|
+
ch.push_back((Character)c);
|
551
|
+
}
|
552
|
+
|
553
|
+
|
554
|
+
/*******************************************************************/
|
555
|
+
/* */
|
556
|
+
/* Alphabet::string2labelseq */
|
557
|
+
/* */
|
558
|
+
/*******************************************************************/
|
559
|
+
|
560
|
+
void Alphabet::string2labelseq( char *s, vector<Label> &labels )
|
561
|
+
|
562
|
+
{
|
563
|
+
Label l;
|
564
|
+
while ((l = next_label(s)) != Label::epsilon)
|
565
|
+
labels.push_back(l);
|
566
|
+
}
|
567
|
+
|
568
|
+
|
569
|
+
/*******************************************************************/
|
570
|
+
/* */
|
571
|
+
/* Alphabet::store */
|
572
|
+
/* */
|
573
|
+
/*******************************************************************/
|
574
|
+
|
575
|
+
void Alphabet::store( FILE *file ) const
|
576
|
+
|
577
|
+
{
|
578
|
+
char c=(utf8)? 1: 0;
|
579
|
+
fputc(c, file);
|
580
|
+
|
581
|
+
// write the symbol mapping
|
582
|
+
Character n=cm.size();
|
583
|
+
fwrite(&n, sizeof(n), 1, file);
|
584
|
+
for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
|
585
|
+
Character c=it->first;
|
586
|
+
char *s=it->second;
|
587
|
+
fwrite(&c, sizeof(c), 1, file);
|
588
|
+
fwrite(s, sizeof(char), strlen(s)+1, file);
|
589
|
+
}
|
590
|
+
|
591
|
+
// write the character pairs
|
592
|
+
n = size();
|
593
|
+
fwrite(&n, sizeof(n), 1, file);
|
594
|
+
for( LabelSet::const_iterator p=ls.begin(); p!=ls.end(); p++ ) {
|
595
|
+
Character c=p->lower_char();
|
596
|
+
fwrite(&c, sizeof(c), 1, file);
|
597
|
+
c = p->upper_char();
|
598
|
+
fwrite(&c, sizeof(c), 1, file);
|
599
|
+
}
|
600
|
+
|
601
|
+
if (ferror(file))
|
602
|
+
throw "Error encountered while writing alphabet to file\n";
|
603
|
+
}
|
604
|
+
|
605
|
+
|
606
|
+
/*******************************************************************/
|
607
|
+
/* */
|
608
|
+
/* Alphabet::read */
|
609
|
+
/* */
|
610
|
+
/*******************************************************************/
|
611
|
+
|
612
|
+
void Alphabet::read( FILE *file )
|
613
|
+
|
614
|
+
{
|
615
|
+
utf8 = (fgetc(file) != 0);
|
616
|
+
|
617
|
+
// read the symbol mapping
|
618
|
+
Character n=0;
|
619
|
+
read_num(&n, sizeof(n), file);
|
620
|
+
for( unsigned i=0; i<n; i++) {
|
621
|
+
char buffer[BUFFER_SIZE];
|
622
|
+
Character c;
|
623
|
+
read_num(&c, sizeof(c), file);
|
624
|
+
if (!read_string(buffer, BUFFER_SIZE, file) ||
|
625
|
+
feof(file) || ferror(file))
|
626
|
+
throw "Error1 occurred while reading alphabet!\n";
|
627
|
+
add_symbol(buffer, c);
|
628
|
+
}
|
629
|
+
|
630
|
+
// read the character pairs
|
631
|
+
read_num(&n, sizeof(n), file);
|
632
|
+
if (ferror(file))
|
633
|
+
throw "Error2 occurred while reading alphabet!\n";
|
634
|
+
for( unsigned i=0; i<n; i++) {
|
635
|
+
Character lc, uc;
|
636
|
+
read_num(&lc, sizeof(lc), file);
|
637
|
+
read_num(&uc, sizeof(uc), file);
|
638
|
+
insert(Label(lc, uc));
|
639
|
+
}
|
640
|
+
if (ferror(file))
|
641
|
+
throw "Error3 occurred while reading alphabet!\n";
|
642
|
+
}
|
643
|
+
|
644
|
+
|
645
|
+
/*******************************************************************/
|
646
|
+
/* */
|
647
|
+
/* Alphabet::compute_score */
|
648
|
+
/* */
|
649
|
+
/*******************************************************************/
|
650
|
+
|
651
|
+
int Alphabet::compute_score( Analysis &ana )
|
652
|
+
|
653
|
+
{
|
654
|
+
// check whether the morpheme boundaries are explicitly marked
|
655
|
+
// with <X> tags
|
656
|
+
int score=0;
|
657
|
+
for( size_t i=0; i<ana.size(); i++ ) {
|
658
|
+
|
659
|
+
// get next symbol
|
660
|
+
const char *sym=write_char(ana[i].lower_char());
|
661
|
+
|
662
|
+
if (strcmp(sym,"<X>") == 0)
|
663
|
+
score--;
|
664
|
+
}
|
665
|
+
if (score < 0)
|
666
|
+
return score;
|
667
|
+
|
668
|
+
// No explicit morphome boundary markers have been found.
|
669
|
+
// Count the number of part-of-speech and PREF tags.
|
670
|
+
for( size_t i=0; i<ana.size(); i++ ) {
|
671
|
+
|
672
|
+
// get next symbol
|
673
|
+
const char *sym=write_char(ana[i].lower_char());
|
674
|
+
|
675
|
+
// Is it not a multi-character symbol
|
676
|
+
if (sym[0] != '<' || sym[1] == 0)
|
677
|
+
continue;
|
678
|
+
|
679
|
+
// Is it a POS tag starting with "+" like <+NN>?
|
680
|
+
if (sym[1] == '+') {
|
681
|
+
const char *t=sym+2;
|
682
|
+
for( ; *t >= 'A' && *t <= 'Z'; t++) ;
|
683
|
+
if (t > sym+2 && *t == '>')
|
684
|
+
return score;
|
685
|
+
}
|
686
|
+
|
687
|
+
// Is it a potential POS tag (i.e. all uppercase)?
|
688
|
+
const char *t = sym+1;
|
689
|
+
for( ; *t >= 'A' && *t <= 'Z'; t++) ;
|
690
|
+
if (t == sym+1 || *t != '>')
|
691
|
+
continue;
|
692
|
+
|
693
|
+
// uppercase symbol found
|
694
|
+
if (strcmp(sym,"<SUFF>") == 0 ||
|
695
|
+
strcmp(sym,"<OLDORTH>") == 0 ||
|
696
|
+
strcmp(sym,"<NEWORTH>") == 0)
|
697
|
+
continue; // not what we are looking for
|
698
|
+
|
699
|
+
// disprefer nouns with prefixes
|
700
|
+
if (strcmp(sym,"<PREF>") == 0)
|
701
|
+
score-=2;
|
702
|
+
|
703
|
+
if (strcmp(sym,"<V>") == 0 || strcmp(sym,"<ADJ>") == 0) {
|
704
|
+
bool is_verb=(strcmp(sym,"<V>")==0);
|
705
|
+
// get the next non-empty symbol
|
706
|
+
Character c=Label::epsilon;
|
707
|
+
size_t k;
|
708
|
+
for( k=i+1; k<ana.size(); k++ )
|
709
|
+
if ((c = ana[k].lower_char()) != Label::epsilon)
|
710
|
+
break;
|
711
|
+
// Is it a participle
|
712
|
+
if (c != Label::epsilon) {
|
713
|
+
sym = write_char(c);
|
714
|
+
if (strcmp(sym,"<OLDORTH>") == 0 || strcmp(sym,"<NEWORTH>") == 0) {
|
715
|
+
for( k++; k<ana.size(); k++ )
|
716
|
+
if ((c = ana[k].lower_char()) != Label::epsilon)
|
717
|
+
break;
|
718
|
+
if (c != Label::epsilon)
|
719
|
+
sym = write_char(c);
|
720
|
+
}
|
721
|
+
if (is_verb &&
|
722
|
+
(strcmp(sym,"<PPres>") == 0 || strcmp(sym,"<PPast>") == 0))
|
723
|
+
continue; // don't consider participles as complex
|
724
|
+
if (!is_verb &&
|
725
|
+
(strcmp(sym,"<Sup>") == 0 || strcmp(sym,"<Comp>") == 0))
|
726
|
+
continue; // don't consider participles as complex
|
727
|
+
}
|
728
|
+
}
|
729
|
+
score--;
|
730
|
+
}
|
731
|
+
return score;
|
732
|
+
}
|
733
|
+
|
734
|
+
|
735
|
+
|
736
|
+
/*******************************************************************/
|
737
|
+
/* */
|
738
|
+
/* Alphabet::disambiguate */
|
739
|
+
/* */
|
740
|
+
/*******************************************************************/
|
741
|
+
|
742
|
+
void Alphabet::disambiguate( vector<Analysis> &analyses )
|
743
|
+
|
744
|
+
{
|
745
|
+
// compute the scores
|
746
|
+
int bestscore=INT_MIN;
|
747
|
+
vector<int> score;
|
748
|
+
|
749
|
+
for( size_t i=0; i<analyses.size(); i++ ) {
|
750
|
+
score.push_back(compute_score(analyses[i]));
|
751
|
+
if (bestscore < score[i])
|
752
|
+
bestscore = score[i];
|
753
|
+
}
|
754
|
+
|
755
|
+
// delete suboptimal analyses
|
756
|
+
size_t k=0;
|
757
|
+
for( size_t i=0; i<analyses.size(); i++ )
|
758
|
+
if (score[i] == bestscore)
|
759
|
+
analyses[k++] = analyses[i];
|
760
|
+
analyses.resize(k);
|
761
|
+
}
|
762
|
+
|
763
|
+
|
764
|
+
|
765
|
+
/*******************************************************************/
|
766
|
+
/* */
|
767
|
+
/* Alphabet::print_analysis */
|
768
|
+
/* */
|
769
|
+
/*******************************************************************/
|
770
|
+
|
771
|
+
char *Alphabet::print_analysis( Analysis &ana, bool both_layers )
|
772
|
+
|
773
|
+
{
|
774
|
+
vector<char> ch;
|
775
|
+
|
776
|
+
// for each transition
|
777
|
+
for( size_t i=0; i<ana.size(); i++ ) {
|
778
|
+
|
779
|
+
// get the transition label
|
780
|
+
Label l=ana[i];
|
781
|
+
const char *s;
|
782
|
+
|
783
|
+
// either print the analysis symbol or the whole label
|
784
|
+
if (both_layers)
|
785
|
+
s = write_label(l);
|
786
|
+
else if (l.lower_char() != Label::epsilon)
|
787
|
+
s = write_char(l.lower_char());
|
788
|
+
else
|
789
|
+
continue;
|
790
|
+
|
791
|
+
// copy the characters to the character array
|
792
|
+
while (*s)
|
793
|
+
ch.push_back(*(s++));
|
794
|
+
}
|
795
|
+
ch.push_back(0); // terminate the string
|
796
|
+
|
797
|
+
static char *result=NULL;
|
798
|
+
if (result != NULL)
|
799
|
+
delete[] result;
|
800
|
+
result = new char[ch.size()];
|
801
|
+
for( size_t i=0; i<ch.size(); i++ )
|
802
|
+
result[i] = ch[i];
|
803
|
+
|
804
|
+
return result;
|
805
|
+
}
|
806
|
+
|
807
|
+
|