mittens 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -0
- data/README.md +2 -2
- data/Rakefile +10 -3
- data/lib/mittens/version.rb +1 -1
- data/vendor/snowball/.github/workflows/ci.yml +144 -17
- data/vendor/snowball/.github/workflows/coverage.yml +117 -0
- data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
- data/vendor/snowball/.gitignore +33 -7
- data/vendor/snowball/CONTRIBUTING.rst +7 -0
- data/vendor/snowball/COPYING +1 -1
- data/vendor/snowball/GNUmakefile +736 -298
- data/vendor/snowball/NEWS +1394 -7
- data/vendor/snowball/README.rst +8 -8
- data/vendor/snowball/ada/generate/generate.adb +5 -5
- data/vendor/snowball/ada/src/stemmer.adb +177 -188
- data/vendor/snowball/ada/src/stemmer.ads +86 -89
- data/vendor/snowball/ada/src/stemwords.adb +21 -5
- data/vendor/snowball/algorithms/czech.sbl +255 -0
- data/vendor/snowball/algorithms/danish.sbl +22 -10
- data/vendor/snowball/algorithms/english.sbl +7 -4
- data/vendor/snowball/algorithms/esperanto.sbl +6 -7
- data/vendor/snowball/algorithms/estonian.sbl +9 -4
- data/vendor/snowball/algorithms/finnish.sbl +33 -21
- data/vendor/snowball/algorithms/german.sbl +5 -0
- data/vendor/snowball/algorithms/indonesian.sbl +115 -96
- data/vendor/snowball/algorithms/italian.sbl +26 -1
- data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
- data/vendor/snowball/algorithms/norwegian.sbl +17 -6
- data/vendor/snowball/algorithms/persian.sbl +387 -0
- data/vendor/snowball/algorithms/polish.sbl +177 -0
- data/vendor/snowball/algorithms/sesotho.sbl +115 -0
- data/vendor/snowball/algorithms/turkish.sbl +4 -4
- data/vendor/snowball/compiler/analyser.c +2002 -711
- data/vendor/snowball/compiler/driver.c +460 -298
- data/vendor/snowball/compiler/generator.c +439 -1965
- data/vendor/snowball/compiler/generator_ada.c +605 -430
- data/vendor/snowball/compiler/generator_c.c +2227 -0
- data/vendor/snowball/compiler/generator_csharp.c +365 -274
- data/vendor/snowball/compiler/generator_dart.c +1476 -0
- data/vendor/snowball/compiler/generator_go.c +348 -270
- data/vendor/snowball/compiler/generator_java.c +330 -233
- data/vendor/snowball/compiler/generator_js.c +534 -385
- data/vendor/snowball/compiler/generator_pascal.c +361 -320
- data/vendor/snowball/compiler/generator_php.c +1445 -0
- data/vendor/snowball/compiler/generator_python.c +399 -299
- data/vendor/snowball/compiler/generator_rust.c +370 -261
- data/vendor/snowball/compiler/generator_zig.c +1474 -0
- data/vendor/snowball/compiler/header.h +153 -86
- data/vendor/snowball/compiler/space.c +121 -63
- data/vendor/snowball/compiler/tokeniser.c +286 -182
- data/vendor/snowball/compiler/tokens.h +71 -0
- data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
- data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
- data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
- data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
- data/vendor/snowball/cxx/.gitignore +4 -0
- data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
- data/vendor/snowball/cxx/stemmer.h +12 -0
- data/vendor/snowball/cxx/stemwords.cxx +176 -0
- data/vendor/snowball/cxx/utilities.cxx +2 -0
- data/vendor/snowball/dart/.gitignore +4 -0
- data/vendor/snowball/dart/analysis_options.yaml +1 -0
- data/vendor/snowball/dart/example/test_app.dart +65 -0
- data/vendor/snowball/dart/generate_algorithms.pl +21 -0
- data/vendor/snowball/dart/lib/snowball.dart +18 -0
- data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
- data/vendor/snowball/dart/pubspec.yaml +17 -0
- data/vendor/snowball/doc/libstemmer_dart_README +37 -0
- data/vendor/snowball/doc/libstemmer_js_README +2 -2
- data/vendor/snowball/doc/libstemmer_php_README +38 -0
- data/vendor/snowball/doc/libstemmer_python_README +3 -3
- data/vendor/snowball/examples/stemwords.c +18 -3
- data/vendor/snowball/go/README.md +12 -4
- data/vendor/snowball/go/env.go +12 -14
- data/vendor/snowball/go/stemwords/main.go +2 -1
- data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
- data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
- data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
- data/vendor/snowball/javascript/base-stemmer.js +219 -252
- data/vendor/snowball/javascript/stemwords.js +86 -58
- data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
- data/vendor/snowball/libstemmer/modules.txt +4 -0
- data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
- data/vendor/snowball/php/base-stemmer.php +453 -0
- data/vendor/snowball/php/stemwords.php +25 -0
- data/vendor/snowball/python/create_init.py +16 -21
- data/vendor/snowball/python/pyproject.toml +3 -0
- data/vendor/snowball/python/setup.py +5 -7
- data/vendor/snowball/python/snowballstemmer/among.py +1 -2
- data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
- data/vendor/snowball/python/stemwords.py +72 -63
- data/vendor/snowball/runtime/api.c +11 -42
- data/vendor/snowball/runtime/api.h +11 -9
- data/vendor/snowball/runtime/snowball_runtime.h +110 -0
- data/vendor/snowball/runtime/utilities.c +282 -106
- data/vendor/snowball/rust/src/main.rs +2 -2
- data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
- data/vendor/snowball/tests/compilertest +62 -0
- data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
- data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
- data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
- data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
- data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
- data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
- data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
- data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
- data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
- data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
- data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
- data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
- data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
- data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
- data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
- data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
- data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
- data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
- data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
- data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
- data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
- data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
- data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
- data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
- data/vendor/snowball/tests/runtime/among.sbl +19 -0
- data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
- data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
- data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
- data/vendor/snowball/tests/runtime/externals.sbl +22 -0
- data/vendor/snowball/tests/runtime/hop.sbl +12 -0
- data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
- data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
- data/vendor/snowball/tests/runtime/naming.sbl +20 -0
- data/vendor/snowball/tests/runtime/not.sbl +30 -0
- data/vendor/snowball/tests/runtime/or.sbl +17 -0
- data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
- data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
- data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
- data/vendor/snowball/tests/runtime/slice.sbl +27 -0
- data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
- data/vendor/snowball/tests/runtime/strings.sbl +66 -0
- data/vendor/snowball/tests/runtime/test.sbl +19 -0
- data/vendor/snowball/tests/stemtest.c +41 -1
- data/vendor/snowball/tests/syntax/canon.sbl +32 -0
- data/vendor/snowball/tests/syntax/canon.stderr +0 -0
- data/vendor/snowball/tests/syntax/canon.syntax +57 -0
- data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
- data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
- data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
- data/vendor/snowball/tests/syntax/inline.sbl +144 -0
- data/vendor/snowball/tests/syntax/inline.stderr +0 -0
- data/vendor/snowball/tests/syntax/inline.syntax +121 -0
- data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
- data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
- data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
- data/vendor/snowball/tests/syntax/loops.sbl +14 -0
- data/vendor/snowball/tests/syntax/loops.stderr +9 -0
- data/vendor/snowball/tests/syntax/loops.syntax +29 -0
- data/vendor/snowball/tests/syntax/noops.sbl +76 -0
- data/vendor/snowball/tests/syntax/noops.stderr +27 -0
- data/vendor/snowball/tests/syntax/noops.syntax +135 -0
- data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
- data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
- data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
- data/vendor/snowball/tests/syntax/unused.sbl +18 -0
- data/vendor/snowball/tests/syntax/unused.stderr +7 -0
- data/vendor/snowball/tests/syntax/unused.syntax +3 -0
- data/vendor/snowball/zig/env.zig +599 -0
- data/vendor/snowball/zig/generate_algorithms.pl +19 -0
- data/vendor/snowball/zig/stemwords.zig +123 -0
- metadata +102 -4
- data/vendor/snowball/compiler/syswords.h +0 -86
- data/vendor/snowball/runtime/header.h +0 -62
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/* This is a simple program which uses the generated C++ stemmers to provide a
|
|
2
|
+
* command line interface for stemming using any of the algorithms provided.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#include <exception>
|
|
6
|
+
#include <fstream>
|
|
7
|
+
#include <iostream>
|
|
8
|
+
|
|
9
|
+
#include <ctype.h> /* for tolower */
|
|
10
|
+
#include <string.h> /* for strcmp */
|
|
11
|
+
|
|
12
|
+
#include "stemmer.h"
|
|
13
|
+
|
|
14
|
+
const char * progname;
|
|
15
|
+
static int pretty = 1;
|
|
16
|
+
|
|
17
|
+
static void
|
|
18
|
+
stem_file(Snowball::Stemmer& stemmer, std::istream& f_in, std::ostream& f_out)
|
|
19
|
+
{
|
|
20
|
+
std::string word;
|
|
21
|
+
|
|
22
|
+
while (true) {
|
|
23
|
+
int ch = f_in.get();
|
|
24
|
+
if (ch < 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
{
|
|
28
|
+
word.clear();
|
|
29
|
+
int inlen = 0;
|
|
30
|
+
while (ch != '\n' && ch >= 0) {
|
|
31
|
+
/* Update count of utf-8 characters. */
|
|
32
|
+
if (ch < 0x80 || ch > 0xBF) inlen += 1;
|
|
33
|
+
/* force lower case: */
|
|
34
|
+
if (ch < 128) ch = tolower(ch);
|
|
35
|
+
|
|
36
|
+
word += ch;
|
|
37
|
+
ch = f_in.get();
|
|
38
|
+
}
|
|
39
|
+
if (pretty) {
|
|
40
|
+
f_out << word;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
word = stemmer(word);
|
|
45
|
+
if (pretty == 1) {
|
|
46
|
+
f_out << " -> ";
|
|
47
|
+
} else if (pretty == 2) {
|
|
48
|
+
if (word.size() > 0) {
|
|
49
|
+
int j;
|
|
50
|
+
if (inlen < 30) {
|
|
51
|
+
for (j = 30 - inlen; j > 0; j--)
|
|
52
|
+
f_out << ' ';
|
|
53
|
+
} else {
|
|
54
|
+
f_out << '\n';
|
|
55
|
+
for (j = 30; j > 0; j--)
|
|
56
|
+
f_out << ' ';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
f_out << word << '\n';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Display the command line syntax, and then exit.
|
|
69
|
+
* @param n The value to exit with.
|
|
70
|
+
*/
|
|
71
|
+
static void
|
|
72
|
+
usage(int n)
|
|
73
|
+
{
|
|
74
|
+
printf("usage: %s [-l <language>] [-i <input file>] [-o <output file>] [-c <character encoding>] [-p[2]] [-h]\n"
|
|
75
|
+
"\n"
|
|
76
|
+
"The input file consists of a list of words to be stemmed, one per\n"
|
|
77
|
+
"line. Words should be in lower case, but (for English) A-Z letters\n"
|
|
78
|
+
"are mapped to their a-z equivalents anyway. If omitted, stdin is\n"
|
|
79
|
+
"used.\n"
|
|
80
|
+
"\n",
|
|
81
|
+
progname);
|
|
82
|
+
printf(
|
|
83
|
+
"If -p is given the output file consists of each word of the input\n"
|
|
84
|
+
"file followed by \"->\" followed by its stemmed equivalent.\n"
|
|
85
|
+
"If -p2 is given the output file is a two column layout containing\n"
|
|
86
|
+
"the input words in the first column and the stemmed equivalents in\n"
|
|
87
|
+
"the second column.\n"
|
|
88
|
+
"Otherwise, the output file consists of the stemmed words, one per\n"
|
|
89
|
+
"line.\n"
|
|
90
|
+
"\n"
|
|
91
|
+
"-h displays this help\n");
|
|
92
|
+
exit(n);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
int
|
|
96
|
+
main(int argc, char * argv[])
|
|
97
|
+
try {
|
|
98
|
+
const char * in = NULL;
|
|
99
|
+
const char * out = NULL;
|
|
100
|
+
const char * language = "english";
|
|
101
|
+
|
|
102
|
+
int i = 1;
|
|
103
|
+
pretty = 0;
|
|
104
|
+
|
|
105
|
+
progname = argv[0];
|
|
106
|
+
|
|
107
|
+
while (i < argc) {
|
|
108
|
+
const char * s = argv[i++];
|
|
109
|
+
if (s[0] == '-') {
|
|
110
|
+
if (strcmp(s, "-o") == 0) {
|
|
111
|
+
if (i >= argc) {
|
|
112
|
+
fprintf(stderr, "%s requires an argument\n", s);
|
|
113
|
+
exit(1);
|
|
114
|
+
}
|
|
115
|
+
out = argv[i++];
|
|
116
|
+
} else if (strcmp(s, "-i") == 0) {
|
|
117
|
+
if (i >= argc) {
|
|
118
|
+
fprintf(stderr, "%s requires an argument\n", s);
|
|
119
|
+
exit(1);
|
|
120
|
+
}
|
|
121
|
+
in = argv[i++];
|
|
122
|
+
} else if (strcmp(s, "-l") == 0) {
|
|
123
|
+
if (i >= argc) {
|
|
124
|
+
fprintf(stderr, "%s requires an argument\n", s);
|
|
125
|
+
exit(1);
|
|
126
|
+
}
|
|
127
|
+
language = argv[i++];
|
|
128
|
+
} else if (strcmp(s, "-p2") == 0) {
|
|
129
|
+
pretty = 2;
|
|
130
|
+
} else if (strcmp(s, "-p") == 0) {
|
|
131
|
+
pretty = 1;
|
|
132
|
+
} else if (strcmp(s, "-h") == 0) {
|
|
133
|
+
usage(0);
|
|
134
|
+
} else {
|
|
135
|
+
fprintf(stderr, "option %s unknown\n", s);
|
|
136
|
+
usage(1);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
fprintf(stderr, "unexpected parameter %s\n", s);
|
|
140
|
+
usage(1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Snowball::Stemmer* stemmer = Snowball::make_stemmer(language);
|
|
145
|
+
if (stemmer == NULL) {
|
|
146
|
+
fprintf(stderr, "language `%s' not available for stemming\n", language);
|
|
147
|
+
exit(1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* prepare the files */
|
|
151
|
+
std::ifstream f_in;
|
|
152
|
+
if (in) {
|
|
153
|
+
f_in.open(in);
|
|
154
|
+
if (!f_in.is_open()) {
|
|
155
|
+
fprintf(stderr, "file %s not found\n", in);
|
|
156
|
+
exit(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
std::ofstream f_out;
|
|
160
|
+
if (out) {
|
|
161
|
+
f_out.open(out);
|
|
162
|
+
if (!f_out.is_open()) {
|
|
163
|
+
fprintf(stderr, "file %s cannot be opened\n", out);
|
|
164
|
+
exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* do the stemming process: */
|
|
169
|
+
stem_file(*stemmer, in ? f_in : std::cin, out ? f_out : std::cout);
|
|
170
|
+
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
catch (const std::exception& e) {
|
|
174
|
+
fprintf(stderr, "Exception: %s\n", e.what());
|
|
175
|
+
exit(1);
|
|
176
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include: package:lints/recommended.yaml
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import 'dart:convert';
|
|
2
|
+
import 'dart:io';
|
|
3
|
+
|
|
4
|
+
import 'package:snowball/snowball.dart';
|
|
5
|
+
|
|
6
|
+
void usage() {
|
|
7
|
+
print("Usage: test_app <algorithm> [<input file>] [-o <output file>]");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
Future<void> main(List<String> args) async {
|
|
11
|
+
if (args.isEmpty) {
|
|
12
|
+
usage();
|
|
13
|
+
exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
final algorithms = Algorithm.values.where((v) => v.name == args[0]);
|
|
17
|
+
if (algorithms.isEmpty) {
|
|
18
|
+
print('Stemmer for ${args[0]} not found');
|
|
19
|
+
exit(1);
|
|
20
|
+
}
|
|
21
|
+
final algorithm = algorithms.first;
|
|
22
|
+
final stemmer = SnowballStemmer(algorithm);
|
|
23
|
+
|
|
24
|
+
int arg = 1;
|
|
25
|
+
|
|
26
|
+
Stream<List<int>> inStream;
|
|
27
|
+
if (args.length > arg && args[arg] != '-o') {
|
|
28
|
+
inStream = File(args[arg++]).openRead();
|
|
29
|
+
} else {
|
|
30
|
+
inStream = stdin;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
IOSink outStream;
|
|
34
|
+
if (args.length > arg) {
|
|
35
|
+
if (args.length != arg + 2 || args[arg] != '-o') {
|
|
36
|
+
usage();
|
|
37
|
+
exit(1);
|
|
38
|
+
}
|
|
39
|
+
outStream = File(args[arg + 1]).openWrite();
|
|
40
|
+
} else {
|
|
41
|
+
outStream = stdout.nonBlocking;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Stream<String> reader = inStream
|
|
45
|
+
.transform(utf8.decoder)
|
|
46
|
+
.transform(LineSplitter());
|
|
47
|
+
|
|
48
|
+
final outBuffer = StringBuffer();
|
|
49
|
+
await for (var line in reader) {
|
|
50
|
+
try {
|
|
51
|
+
final stem = stemmer.stem(line);
|
|
52
|
+
outBuffer.writeln(stem);
|
|
53
|
+
if (outBuffer.length > 8192) {
|
|
54
|
+
outStream.write(outBuffer);
|
|
55
|
+
outBuffer.clear();
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
print('Failed to stem word "$line"');
|
|
59
|
+
rethrow;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (outBuffer.isNotEmpty) outStream.write(outBuffer);
|
|
63
|
+
await outStream.flush();
|
|
64
|
+
await outStream.close();
|
|
65
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env perl
|
|
2
|
+
use strict;
|
|
3
|
+
use warnings;
|
|
4
|
+
|
|
5
|
+
my @algorithms = @ARGV;
|
|
6
|
+
|
|
7
|
+
# Generate the lib/src/algorithms.dart file from modules.txt
|
|
8
|
+
print("// ignore_for_file: constant_identifier_names\n\n");
|
|
9
|
+
print("import 'package:snowball/src/snowball.dart';\n\n");
|
|
10
|
+
foreach my $algorithm (@algorithms) {
|
|
11
|
+
print("import '../ext/${algorithm}_stemmer.dart';\n");
|
|
12
|
+
}
|
|
13
|
+
print("\nenum Algorithm {\n");
|
|
14
|
+
foreach my $algorithm (@algorithms) {
|
|
15
|
+
print(" $algorithm,\n");
|
|
16
|
+
}
|
|
17
|
+
print("}\n\nfinal stemmers = <Algorithm, SnowballStemmer>{\n");
|
|
18
|
+
foreach my $algorithm (@algorithms) {
|
|
19
|
+
print(" Algorithm.$algorithm: ${algorithm}_stemmer(),\n");
|
|
20
|
+
}
|
|
21
|
+
print("};\n");
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// ignore_for_file: non_constant_identifier_names, curly_braces_in_flow_control_structures
|
|
2
|
+
|
|
3
|
+
library;
|
|
4
|
+
|
|
5
|
+
import 'src/algorithms.dart';
|
|
6
|
+
export 'src/algorithms.dart';
|
|
7
|
+
import 'src/snowball.dart' as impl;
|
|
8
|
+
|
|
9
|
+
class SnowballStemmer {
|
|
10
|
+
final impl.SnowballStemmer _stemmer;
|
|
11
|
+
|
|
12
|
+
SnowballStemmer(Algorithm algorithm) : _stemmer = stemmers[algorithm]!;
|
|
13
|
+
String stem(String s) {
|
|
14
|
+
_stemmer.init(s);
|
|
15
|
+
_stemmer.stem();
|
|
16
|
+
return _stemmer.current;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// ignore_for_file: non_constant_identifier_names, curly_braces_in_flow_control_structures
|
|
2
|
+
|
|
3
|
+
library;
|
|
4
|
+
|
|
5
|
+
/// Internal class used by Snowball stemmers
|
|
6
|
+
class Among {
|
|
7
|
+
Among(this.s, this.substring_i, this.result, [this.function_index = 0]);
|
|
8
|
+
|
|
9
|
+
/// search string
|
|
10
|
+
final String s;
|
|
11
|
+
|
|
12
|
+
/// index to longest matching substring
|
|
13
|
+
final int substring_i;
|
|
14
|
+
|
|
15
|
+
/// result of the lookup
|
|
16
|
+
final int result;
|
|
17
|
+
|
|
18
|
+
/// function index, 0 if none
|
|
19
|
+
final int function_index;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class SnowballProgram {
|
|
23
|
+
String current = '';
|
|
24
|
+
|
|
25
|
+
int cursor = 0;
|
|
26
|
+
int limit = 0;
|
|
27
|
+
int limit_backward = 0;
|
|
28
|
+
int bra = 0;
|
|
29
|
+
int ket = 0;
|
|
30
|
+
int af = 0;
|
|
31
|
+
|
|
32
|
+
SnowballProgram();
|
|
33
|
+
|
|
34
|
+
SnowballProgram.from(SnowballProgram other)
|
|
35
|
+
: current = other.current,
|
|
36
|
+
cursor = other.cursor,
|
|
37
|
+
limit = other.limit,
|
|
38
|
+
limit_backward = other.limit_backward,
|
|
39
|
+
bra = other.bra,
|
|
40
|
+
ket = other.ket,
|
|
41
|
+
af = other.af;
|
|
42
|
+
|
|
43
|
+
void init(String s) {
|
|
44
|
+
current = s;
|
|
45
|
+
cursor = 0;
|
|
46
|
+
limit = current.length;
|
|
47
|
+
limit_backward = 0;
|
|
48
|
+
bra = cursor;
|
|
49
|
+
ket = limit;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void copy_from(SnowballProgram other) {
|
|
53
|
+
current = other.current;
|
|
54
|
+
cursor = other.cursor;
|
|
55
|
+
limit = other.limit;
|
|
56
|
+
limit_backward = other.limit_backward;
|
|
57
|
+
bra = other.bra;
|
|
58
|
+
ket = other.ket;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
bool in_grouping(String s, int min, int max) {
|
|
62
|
+
if (cursor >= limit) return false;
|
|
63
|
+
int ch = current.codeUnitAt(cursor);
|
|
64
|
+
if (ch > max || ch < min) return false;
|
|
65
|
+
ch -= min;
|
|
66
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) return false;
|
|
67
|
+
cursor++;
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
bool go_in_grouping(String s, int min, int max) {
|
|
72
|
+
while (cursor < limit) {
|
|
73
|
+
int ch = current.codeUnitAt(cursor);
|
|
74
|
+
if (ch > max || ch < min) return true;
|
|
75
|
+
ch -= min;
|
|
76
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) return true;
|
|
77
|
+
cursor++;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
bool in_grouping_b(String s, int min, int max) {
|
|
83
|
+
if (cursor <= limit_backward) return false;
|
|
84
|
+
int ch = current.codeUnitAt(cursor - 1);
|
|
85
|
+
if (ch > max || ch < min) return false;
|
|
86
|
+
ch -= min;
|
|
87
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) return false;
|
|
88
|
+
cursor--;
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
bool go_in_grouping_b(String s, int min, int max) {
|
|
93
|
+
while (cursor > limit_backward) {
|
|
94
|
+
int ch = current.codeUnitAt(cursor - 1);
|
|
95
|
+
if (ch > max || ch < min) return true;
|
|
96
|
+
ch -= min;
|
|
97
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) return true;
|
|
98
|
+
cursor--;
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bool out_grouping(String s, int min, int max) {
|
|
104
|
+
if (cursor >= limit) return false;
|
|
105
|
+
int ch = current.codeUnitAt(cursor);
|
|
106
|
+
if (ch > max || ch < min) {
|
|
107
|
+
cursor++;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
ch -= min;
|
|
111
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) {
|
|
112
|
+
cursor++;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
bool go_out_grouping(String s, int min, int max) {
|
|
119
|
+
while (cursor < limit) {
|
|
120
|
+
int ch = current.codeUnitAt(cursor);
|
|
121
|
+
if (ch <= max && ch >= min) {
|
|
122
|
+
ch -= min;
|
|
123
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) != 0) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
cursor++;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
bool out_grouping_b(String s, int min, int max) {
|
|
133
|
+
if (cursor <= limit_backward) return false;
|
|
134
|
+
int ch = current.codeUnitAt(cursor - 1);
|
|
135
|
+
if (ch > max || ch < min) {
|
|
136
|
+
cursor--;
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
ch -= min;
|
|
140
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) == 0) {
|
|
141
|
+
cursor--;
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
bool go_out_grouping_b(String s, int min, int max) {
|
|
148
|
+
while (cursor > limit_backward) {
|
|
149
|
+
int ch = current.codeUnitAt(cursor - 1);
|
|
150
|
+
if (ch <= max && ch >= min) {
|
|
151
|
+
ch -= min;
|
|
152
|
+
if ((s.codeUnitAt(ch >> 3) & (0X1 << (ch & 0X7))) != 0) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
cursor--;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
bool eq_s(String s) {
|
|
162
|
+
if (limit - cursor < s.length) return false;
|
|
163
|
+
if (!current.startsWith(s, cursor)) return false;
|
|
164
|
+
cursor += s.length;
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
bool eq_s_b(String s) {
|
|
169
|
+
if (cursor - limit_backward < s.length) return false;
|
|
170
|
+
if (!current.substring(0, cursor).endsWith(s)) return false;
|
|
171
|
+
cursor -= s.length;
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
int find_among(List<Among> v, bool Function()? call_among_func) {
|
|
176
|
+
int i = 0;
|
|
177
|
+
int j = v.length;
|
|
178
|
+
|
|
179
|
+
int c = cursor;
|
|
180
|
+
int l = limit;
|
|
181
|
+
|
|
182
|
+
int common_i = 0;
|
|
183
|
+
int common_j = 0;
|
|
184
|
+
|
|
185
|
+
bool first_key_inspected = false;
|
|
186
|
+
|
|
187
|
+
while (true) {
|
|
188
|
+
int k = i + ((j - i) >> 1);
|
|
189
|
+
int diff = 0;
|
|
190
|
+
int common = common_i < common_j ? common_i : common_j; // smaller
|
|
191
|
+
Among w = v[k];
|
|
192
|
+
for (int i2 = common; i2 < w.s.length; i2++) {
|
|
193
|
+
if (c + common == l) {
|
|
194
|
+
diff = -1;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
diff = current.codeUnitAt(c + common) - w.s.codeUnitAt(i2);
|
|
198
|
+
if (diff != 0) break;
|
|
199
|
+
common++;
|
|
200
|
+
}
|
|
201
|
+
if (diff < 0) {
|
|
202
|
+
j = k;
|
|
203
|
+
common_j = common;
|
|
204
|
+
} else {
|
|
205
|
+
i = k;
|
|
206
|
+
common_i = common;
|
|
207
|
+
}
|
|
208
|
+
if (j - i <= 1) {
|
|
209
|
+
if (i > 0) break; // v->s has been inspected
|
|
210
|
+
if (j == i) break; // only one item in v
|
|
211
|
+
|
|
212
|
+
// - but now we need to go round once more to get
|
|
213
|
+
// v->s inspected. This looks messy, but is actually
|
|
214
|
+
// the optimal approach.
|
|
215
|
+
|
|
216
|
+
if (first_key_inspected) break;
|
|
217
|
+
first_key_inspected = true;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
while (true) {
|
|
221
|
+
Among w = v[i];
|
|
222
|
+
if (common_i >= w.s.length) {
|
|
223
|
+
cursor = c + w.s.length;
|
|
224
|
+
if (w.function_index == 0) return w.result;
|
|
225
|
+
af = w.function_index;
|
|
226
|
+
if (call_among_func?.call() ?? false) {
|
|
227
|
+
cursor = c + w.s.length;
|
|
228
|
+
return w.result;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
i = w.substring_i;
|
|
232
|
+
if (i < 0) return 0;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
int find_among_b(List<Among> v, bool Function()? call_among_func) {
|
|
237
|
+
int i = 0;
|
|
238
|
+
int j = v.length;
|
|
239
|
+
|
|
240
|
+
int c = cursor;
|
|
241
|
+
int lb = limit_backward;
|
|
242
|
+
|
|
243
|
+
int common_i = 0;
|
|
244
|
+
int common_j = 0;
|
|
245
|
+
|
|
246
|
+
bool first_key_inspected = false;
|
|
247
|
+
|
|
248
|
+
while (true) {
|
|
249
|
+
int k = i + ((j - i) >> 1);
|
|
250
|
+
int diff = 0;
|
|
251
|
+
int common = common_i < common_j ? common_i : common_j;
|
|
252
|
+
Among w = v[k];
|
|
253
|
+
for (int i2 = w.s.length - 1 - common; i2 >= 0; i2--) {
|
|
254
|
+
if (c - common == lb) {
|
|
255
|
+
diff = -1;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
diff = current.codeUnitAt(c - 1 - common) - w.s.codeUnitAt(i2);
|
|
259
|
+
if (diff != 0) break;
|
|
260
|
+
common++;
|
|
261
|
+
}
|
|
262
|
+
if (diff < 0) {
|
|
263
|
+
j = k;
|
|
264
|
+
common_j = common;
|
|
265
|
+
} else {
|
|
266
|
+
i = k;
|
|
267
|
+
common_i = common;
|
|
268
|
+
}
|
|
269
|
+
if (j - i <= 1) {
|
|
270
|
+
if (i > 0) break;
|
|
271
|
+
if (j == i) break;
|
|
272
|
+
if (first_key_inspected) break;
|
|
273
|
+
first_key_inspected = true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
while (true) {
|
|
277
|
+
Among w = v[i];
|
|
278
|
+
if (common_i >= w.s.length) {
|
|
279
|
+
cursor = c - w.s.length;
|
|
280
|
+
if (w.function_index == 0) return w.result;
|
|
281
|
+
af = w.function_index;
|
|
282
|
+
if (call_among_func?.call() ?? false) {
|
|
283
|
+
cursor = c - w.s.length;
|
|
284
|
+
return w.result;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
i = w.substring_i;
|
|
288
|
+
if (i < 0) return 0;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
int replace_s(int c_bra, int c_ket, String s) {
|
|
293
|
+
final adjustment = s.length - (c_ket - c_bra);
|
|
294
|
+
current = current.replaceRange(c_bra, c_ket, s);
|
|
295
|
+
limit += adjustment;
|
|
296
|
+
if (cursor >= c_ket) {
|
|
297
|
+
cursor += adjustment;
|
|
298
|
+
} else if (cursor > c_bra) {
|
|
299
|
+
cursor = c_bra;
|
|
300
|
+
}
|
|
301
|
+
return adjustment;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
void slice_check() {
|
|
305
|
+
assert(bra >= 0, 'bra=$bra');
|
|
306
|
+
assert(bra <= ket, 'bra=$bra,ket=$ket');
|
|
307
|
+
assert(ket <= limit, 'ket=$ket,limit=$limit');
|
|
308
|
+
assert(limit <= current.length, 'limit=$limit,length=${current.length}');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void slice_from(String s) {
|
|
312
|
+
slice_check();
|
|
313
|
+
replace_s(bra, ket, s);
|
|
314
|
+
ket = bra + s.length;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
void slice_del() {
|
|
318
|
+
slice_from("");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
void insert(int c_bra, int c_ket, String s) {
|
|
322
|
+
int adjustment = replace_s(c_bra, c_ket, s);
|
|
323
|
+
if (c_bra <= bra) bra += adjustment;
|
|
324
|
+
if (c_bra <= ket) ket += adjustment;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
String slice_to() {
|
|
328
|
+
slice_check();
|
|
329
|
+
return current.substring(bra, ket);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
String assign_to() {
|
|
333
|
+
return current.substring(0, limit);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
abstract class SnowballStemmer extends SnowballProgram {
|
|
338
|
+
bool stem();
|
|
339
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: snowball
|
|
2
|
+
description: This package provides stemmers generated from Snowball algorithms.
|
|
3
|
+
version: 3.1.1 # SNOWBALL_VERSION
|
|
4
|
+
repository: https://github.com/snowballstem/snowball
|
|
5
|
+
issue_tracker: https://github.com/snowballstem/snowball/issues
|
|
6
|
+
topics:
|
|
7
|
+
- stemmer
|
|
8
|
+
|
|
9
|
+
environment:
|
|
10
|
+
sdk: ^3.8.1
|
|
11
|
+
|
|
12
|
+
dependencies:
|
|
13
|
+
# path: ^1.8.0
|
|
14
|
+
|
|
15
|
+
dev_dependencies:
|
|
16
|
+
lints: ^5.0.0
|
|
17
|
+
test: ^1.24.0
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# snowball
|
|
2
|
+
|
|
3
|
+
This package provides stemmers generated from Snowball algorithms.
|
|
4
|
+
|
|
5
|
+
### What is Stemming?
|
|
6
|
+
|
|
7
|
+
Stemming maps different forms of the same word to a common "stem" - for
|
|
8
|
+
example, the English stemmer maps *connection*, *connections*, *connective*,
|
|
9
|
+
*connected*, and *connecting* to *connect*. So a search for *connected*
|
|
10
|
+
would also find documents which only have the other forms.
|
|
11
|
+
|
|
12
|
+
This stem form is often a word itself, but this is not always the case as this
|
|
13
|
+
is not a requirement for text search systems, which are the intended field of
|
|
14
|
+
use. We also aim to conflate words with the same meaning, rather than all
|
|
15
|
+
words with a common linguistic root (so *awe* and *awful* don't have the same
|
|
16
|
+
stem), and over-stemming is more problematic than under-stemming so we tend not
|
|
17
|
+
to stem in cases that are hard to resolve. If you want to always reduce words
|
|
18
|
+
to a root form and/or get a root form which is itself a word then Snowball's
|
|
19
|
+
stemming algorithms likely aren't the right answer.
|
|
20
|
+
|
|
21
|
+
### How to use library
|
|
22
|
+
|
|
23
|
+
The stemming algorithms generally expect the input text to use composed accents
|
|
24
|
+
(Unicode NFC or NFKC) and to have been folded to lower case already.
|
|
25
|
+
|
|
26
|
+
The ``snowball`` package has two functions.
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
import 'package:snowball/snowball.dart';
|
|
30
|
+
|
|
31
|
+
final stemmer = SnowballStemmer(Algorithm.english);
|
|
32
|
+
print(stemmer.stem('walking'));
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Generally you should create a stemmer object and reuse it rather than creating
|
|
36
|
+
a fresh object for each word stemmed (since there's some cost to creating and
|
|
37
|
+
destroying the object).
|
|
@@ -30,9 +30,9 @@ with node:
|
|
|
30
30
|
|
|
31
31
|
.. code-block:: javascript
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
let EnglishStemmer = require('english-stemmer.js');
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
let stemmer = new EnglishStemmer();
|
|
36
36
|
console.log(stemmer.stemWord("testing"));
|
|
37
37
|
|
|
38
38
|
You'll need to bundle ``base-stemmer.js`` and whichever languages you want
|