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,453 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
abstract class SnowballStemmer {
|
|
3
|
+
|
|
4
|
+
protected string $current = '';
|
|
5
|
+
protected int $cursor = 0;
|
|
6
|
+
protected int $limit = 0;
|
|
7
|
+
protected int $limit_backward = 0;
|
|
8
|
+
protected int $bra = 0;
|
|
9
|
+
protected int $ket = 0;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
abstract public function stem(): bool;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
protected function copyFrom(self $other): void {
|
|
16
|
+
$this->current = $other->current;
|
|
17
|
+
$this->cursor = $other->cursor;
|
|
18
|
+
$this->limit = $other->limit;
|
|
19
|
+
$this->limit_backward = $other->limit_backward;
|
|
20
|
+
$this->bra = $other->bra;
|
|
21
|
+
$this->ket = $other->ket;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param int[] $s
|
|
27
|
+
*/
|
|
28
|
+
protected function in_grouping(array $s): bool {
|
|
29
|
+
if ($this->cursor >= $this->limit) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
$ch = $this->charAt();
|
|
33
|
+
if (!array_key_exists($ch, $s)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
$this->cursor += strlen($ch);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param int[] $s
|
|
43
|
+
*/
|
|
44
|
+
protected function go_in_grouping(array $s): bool {
|
|
45
|
+
while ($this->cursor < $this->limit) {
|
|
46
|
+
$ch = $this->charAt();
|
|
47
|
+
if (!array_key_exists($ch, $s)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
$this->cursor += strlen($ch);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param int[] $s
|
|
59
|
+
*/
|
|
60
|
+
protected function in_grouping_b(array $s): bool {
|
|
61
|
+
if ($this->cursor <= $this->limit_backward) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
$ch = $this->charBefore();
|
|
65
|
+
if (!array_key_exists($ch, $s)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
$this->cursor -= strlen($ch);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param int[] $s
|
|
75
|
+
*/
|
|
76
|
+
protected function go_in_grouping_b(array $s): bool {
|
|
77
|
+
while ($this->cursor > $this->limit_backward) {
|
|
78
|
+
$ch = $this->charBefore();
|
|
79
|
+
if (!array_key_exists($ch, $s)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
$this->cursor -= strlen($ch);
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param int[] $s
|
|
90
|
+
*/
|
|
91
|
+
protected function out_grouping(array $s): bool {
|
|
92
|
+
if ($this->cursor >= $this->limit) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
$ch = $this->charAt();
|
|
96
|
+
if (!array_key_exists($ch, $s)) {
|
|
97
|
+
$this->cursor += strlen($ch);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param int[] $s
|
|
106
|
+
*/
|
|
107
|
+
protected function go_out_grouping(array $s): bool {
|
|
108
|
+
while ($this->cursor < $this->limit) {
|
|
109
|
+
$ch = $this->charAt();
|
|
110
|
+
if (array_key_exists($ch, $s)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
$this->cursor += strlen($ch);
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param int[] $s
|
|
121
|
+
*/
|
|
122
|
+
protected function out_grouping_b(array $s): bool {
|
|
123
|
+
if ($this->cursor <= $this->limit_backward) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
$ch = $this->charBefore();
|
|
127
|
+
if (!array_key_exists($ch, $s)) {
|
|
128
|
+
$this->cursor -= strlen($ch);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param int[] $s
|
|
137
|
+
*/
|
|
138
|
+
protected function go_out_grouping_b(array $s): bool {
|
|
139
|
+
while ($this->cursor > $this->limit_backward) {
|
|
140
|
+
$ch = $this->charBefore();
|
|
141
|
+
if (array_key_exists($ch, $s)) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
$this->cursor -= strlen($ch);
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
protected function eq_s(string $s): bool {
|
|
151
|
+
$slength = strlen($s);
|
|
152
|
+
if ($this->limit - $this->cursor < $slength) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (substr_compare($this->current, $s, $this->cursor, $slength) != 0) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
$this->cursor += $slength;
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
protected function eq_s_b(string $s): bool {
|
|
164
|
+
$slength = strlen($s);
|
|
165
|
+
if ($this->cursor - $this->limit_backward < $slength) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (substr_compare($this->current, $s, $this->cursor - $slength, $slength) != 0) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
$this->cursor -= $slength;
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param array[] $v
|
|
178
|
+
*/
|
|
179
|
+
protected function find_among(array $v): int {
|
|
180
|
+
$i = 0;
|
|
181
|
+
$j = count($v);
|
|
182
|
+
|
|
183
|
+
$c = $this->cursor;
|
|
184
|
+
$l = $this->limit;
|
|
185
|
+
|
|
186
|
+
$common_i = 0;
|
|
187
|
+
$common_j = 0;
|
|
188
|
+
|
|
189
|
+
$first_key_inspected = false;
|
|
190
|
+
|
|
191
|
+
while (true) {
|
|
192
|
+
$k = $i + (($j-$i) >> 1);
|
|
193
|
+
$diff = 0;
|
|
194
|
+
$common = min($common_i, $common_j); // smaller
|
|
195
|
+
// w[0]: string, w[1]: substring_i, w[2]: result, w[3]: function (optional)
|
|
196
|
+
$w = $v[$k];
|
|
197
|
+
$w0length = strlen($w[0]);
|
|
198
|
+
for ($i2 = $common; $i2 < $w0length; $i2++) {
|
|
199
|
+
if ($c + $common === $l) {
|
|
200
|
+
$diff = -1;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
$diff = strcmp($this->current[$c+$common], $w[0][$i2]);
|
|
204
|
+
if ($diff !== 0) {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
$common++;
|
|
208
|
+
}
|
|
209
|
+
if ($diff < 0) {
|
|
210
|
+
$j = $k;
|
|
211
|
+
$common_j = $common;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
$i = $k;
|
|
215
|
+
$common_i = $common;
|
|
216
|
+
}
|
|
217
|
+
if ($j - $i <= 1) {
|
|
218
|
+
if ($i > 0) {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
// v->s has been inspected
|
|
222
|
+
if ($j === $i) {
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
// only one item in v
|
|
226
|
+
|
|
227
|
+
// - but now we need to go round once more to get
|
|
228
|
+
// v->s inspected. This looks messy, but is actually
|
|
229
|
+
// the optimal approach.
|
|
230
|
+
|
|
231
|
+
if ($first_key_inspected) {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
$first_key_inspected = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
do {
|
|
238
|
+
$w = $v[$i];
|
|
239
|
+
$w0length = strlen($w[0]);
|
|
240
|
+
if ($common_i >= $w0length) {
|
|
241
|
+
$this->cursor = $c + $w0length;
|
|
242
|
+
if (count($w) < 4) {
|
|
243
|
+
return $w[2];
|
|
244
|
+
}
|
|
245
|
+
$res = $this->{$w[3]}();
|
|
246
|
+
$this->cursor = $c + $w0length;
|
|
247
|
+
if ($res) {
|
|
248
|
+
return $w[2];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
$i = $w[1];
|
|
252
|
+
} while ($i >= 0);
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* find_among_b is for backwards processing. Same comments apply
|
|
259
|
+
*/
|
|
260
|
+
protected function find_among_b(array $v): int {
|
|
261
|
+
$i = 0;
|
|
262
|
+
$j = count($v);
|
|
263
|
+
|
|
264
|
+
$c = $this->cursor;
|
|
265
|
+
$lb = $this->limit_backward;
|
|
266
|
+
|
|
267
|
+
$common_i = 0;
|
|
268
|
+
$common_j = 0;
|
|
269
|
+
|
|
270
|
+
$first_key_inspected = false;
|
|
271
|
+
|
|
272
|
+
while (true) {
|
|
273
|
+
$k = $i + (($j-$i) >> 1);
|
|
274
|
+
$diff = 0;
|
|
275
|
+
$common = min($common_i, $common_j);
|
|
276
|
+
$w = $v[$k];
|
|
277
|
+
$w0length = strlen($w[0]);
|
|
278
|
+
for ($i2 = $w0length - 1 - $common; $i2 >= 0; $i2--) {
|
|
279
|
+
if ($c - $common == $lb) {
|
|
280
|
+
$diff = -1;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
$diff = strcmp($this->current[$c - 1 - $common], $w[0][$i2]);
|
|
284
|
+
if ($diff != 0) {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
$common++;
|
|
288
|
+
}
|
|
289
|
+
if ($diff < 0) {
|
|
290
|
+
$j = $k;
|
|
291
|
+
$common_j = $common;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
$i = $k;
|
|
295
|
+
$common_i = $common;
|
|
296
|
+
}
|
|
297
|
+
if ($j - $i <= 1) {
|
|
298
|
+
if ($i > 0 || $j === $i || $first_key_inspected) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
$first_key_inspected = true;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
do {
|
|
305
|
+
$w = $v[$i];
|
|
306
|
+
$w0length = strlen($w[0]);
|
|
307
|
+
if ($common_i >= $w0length) {
|
|
308
|
+
$this->cursor = $c - $w0length;
|
|
309
|
+
if (count($w) < 4) {
|
|
310
|
+
return $w[2];
|
|
311
|
+
}
|
|
312
|
+
$res = $this->{$w[3]}();
|
|
313
|
+
$this->cursor = $c - $w0length;
|
|
314
|
+
if ($res) {
|
|
315
|
+
return $w[2];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
$i = $w[1];
|
|
319
|
+
} while ($i >= 0);
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* to replace chars between $c_bra and $c_ket in $this->current by the chars in $s.
|
|
326
|
+
*/
|
|
327
|
+
private function replace_s(int $c_bra, int $c_ket, string $s): int {
|
|
328
|
+
$slength = strlen($s);
|
|
329
|
+
$adjustment = $slength - ($c_ket - $c_bra);
|
|
330
|
+
$this->current = substr_replace($this->current, $s, $c_bra, $c_ket - $c_bra);
|
|
331
|
+
$this->limit += $adjustment;
|
|
332
|
+
if ($this->cursor >= $c_ket) {
|
|
333
|
+
$this->cursor += $adjustment;
|
|
334
|
+
} elseif ($this->cursor > $c_bra) {
|
|
335
|
+
$this->cursor = $c_bra;
|
|
336
|
+
}
|
|
337
|
+
return $adjustment;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
private function slice_check(): void {
|
|
342
|
+
if (
|
|
343
|
+
$this->bra < 0 ||
|
|
344
|
+
$this->bra > $this->ket ||
|
|
345
|
+
$this->ket > $this->limit ||
|
|
346
|
+
$this->limit > strlen($this->current)
|
|
347
|
+
) {
|
|
348
|
+
throw new LogicException('Faulty slice operation');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
protected function slice_from(string $s): void {
|
|
354
|
+
$this->slice_check();
|
|
355
|
+
$this->replace_s($this->bra, $this->ket, $s);
|
|
356
|
+
$this->ket = $this->bra + strlen($s);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
protected function slice_del(): void {
|
|
361
|
+
$this->slice_from('');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
protected function insert(int $c_bra, int $c_ket, string $s): void {
|
|
366
|
+
$adjustment = $this->replace_s($c_bra, $c_ket, $s);
|
|
367
|
+
$c_bra <= $this->bra and $this->bra += $adjustment;
|
|
368
|
+
$c_bra <= $this->ket and $this->ket += $adjustment;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
protected function slice_to(): string {
|
|
373
|
+
$this->slice_check();
|
|
374
|
+
return substr($this->current, $this->bra, $this->ket - $this->bra);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private function charAt(): string {
|
|
378
|
+
$s = $this->current[$this->cursor];
|
|
379
|
+
$c = ord($s);
|
|
380
|
+
if ($c < 0xc0) return $s;
|
|
381
|
+
if ($c < 0xe0) return substr($this->current, $this->cursor, 2);
|
|
382
|
+
if ($c < 0xf0) return substr($this->current, $this->cursor, 3);
|
|
383
|
+
return substr($this->current, $this->cursor, 4);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private function charBefore(): string {
|
|
387
|
+
$s = $this->current[$this->cursor - 1];
|
|
388
|
+
if (ord($s) < 0x80) return $s;
|
|
389
|
+
$o = $this->cursor - 1;
|
|
390
|
+
while (--$o && ord($this->current[$o]) < 0xc0) { }
|
|
391
|
+
return substr($this->current, $o, $this->cursor - $o);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
protected function inc_cursor(): void {
|
|
395
|
+
do ++$this->cursor; while ($this->cursor < $this->limit && (ord($this->current[$this->cursor]) & 0xc0) == 0x80);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
protected function dec_cursor(): void {
|
|
399
|
+
do --$this->cursor; while ($this->cursor > $this->limit_backward && (ord($this->current[$this->cursor]) & 0xc0) == 0x80);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
protected function hop(int $delta): bool {
|
|
403
|
+
$res = $this->cursor;
|
|
404
|
+
while ($delta > 0) {
|
|
405
|
+
$delta--;
|
|
406
|
+
if ($res >= $this->limit) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
do {
|
|
410
|
+
$res++;
|
|
411
|
+
} while ($res < $this->limit && (ord($this->current[$res]) & 0xc0) == 0x80);
|
|
412
|
+
}
|
|
413
|
+
$this->cursor = $res;
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
protected function hop_checked(int $delta): bool {
|
|
418
|
+
return $delta >= 0 && $this->hop($delta);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
protected function hop_back(int $delta): bool {
|
|
422
|
+
$res = $this->cursor;
|
|
423
|
+
while ($delta > 0) {
|
|
424
|
+
$delta--;
|
|
425
|
+
if ($res <= $this->limit_backward) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
do {
|
|
429
|
+
$res--;
|
|
430
|
+
} while ($res > $this->limit_backward && (ord($this->current[$res]) & 0xc0) == 0x80);
|
|
431
|
+
}
|
|
432
|
+
$this->cursor = $res;
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
protected function hop_back_checked(int $delta): bool {
|
|
437
|
+
return $delta >= 0 && $this->hop_back($delta);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Public entry point for stemming a word
|
|
442
|
+
*/
|
|
443
|
+
public function stemWord(string $word): string {
|
|
444
|
+
$this->current = $word;
|
|
445
|
+
$this->cursor = 0;
|
|
446
|
+
$this->limit = strlen($word);
|
|
447
|
+
$this->limit_backward = 0;
|
|
448
|
+
$this->bra = $this->cursor;
|
|
449
|
+
$this->ket = $this->limit;
|
|
450
|
+
$this->stem();
|
|
451
|
+
return $this->current;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
$lang = $argv[1] ?? 'english';
|
|
4
|
+
$parent = realpath(__DIR__.'/..');
|
|
5
|
+
$phpfile = $parent.'/php_out/'.$lang.'-stemmer.php';
|
|
6
|
+
if (!file_exists($phpfile)) {
|
|
7
|
+
fwrite(STDERR, "PHP stemmer not found at $phpfile\n");
|
|
8
|
+
exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
require __DIR__.'/base-stemmer.php';
|
|
12
|
+
require $phpfile;
|
|
13
|
+
|
|
14
|
+
$class = 'Snowball'.implode('', array_map('ucfirst', explode('_', $lang))).'Stemmer';
|
|
15
|
+
if (!class_exists($class)) {
|
|
16
|
+
fwrite(STDERR, "$class not included from $phpfile\n");
|
|
17
|
+
exit(1);
|
|
18
|
+
}
|
|
19
|
+
$stemmer = new $class;
|
|
20
|
+
|
|
21
|
+
while ($word = fgets(STDIN)) {
|
|
22
|
+
$word = strtolower(rtrim($word, "\n"));
|
|
23
|
+
$stem = $stemmer->stemWord($word);
|
|
24
|
+
echo $stem, "\n";
|
|
25
|
+
}
|
|
@@ -16,8 +16,8 @@ for pyscript in os.listdir(python_out_folder):
|
|
|
16
16
|
if (match):
|
|
17
17
|
langname = match.group(1)
|
|
18
18
|
titlecase = re.sub(r"_", "", langname.title())
|
|
19
|
-
languages.append("
|
|
20
|
-
imports.append('from .%(lang)s_stemmer import %(title)sStemmer' % {'lang': langname, 'title': titlecase})
|
|
19
|
+
languages.append(" '%(lang)s': %(title)sStemmer," % {'lang': langname, 'title': titlecase})
|
|
20
|
+
imports.append(' from .%(lang)s_stemmer import %(title)sStemmer' % {'lang': langname, 'title': titlecase})
|
|
21
21
|
imports.sort()
|
|
22
22
|
languages.sort()
|
|
23
23
|
|
|
@@ -26,31 +26,26 @@ if len(languages) == 0:
|
|
|
26
26
|
|
|
27
27
|
src = '''__all__ = ('language', 'stemmer')
|
|
28
28
|
|
|
29
|
-
%(imports)s
|
|
30
|
-
|
|
31
|
-
_languages = {
|
|
32
|
-
%(languages)s
|
|
33
|
-
}
|
|
34
|
-
|
|
35
29
|
try:
|
|
36
30
|
import Stemmer
|
|
37
|
-
|
|
31
|
+
algorithms = Stemmer.algorithms
|
|
32
|
+
stemmer = Stemmer.Stemmer
|
|
38
33
|
except ImportError:
|
|
39
|
-
|
|
34
|
+
%(imports)s
|
|
35
|
+
|
|
36
|
+
_languages = {
|
|
37
|
+
%(languages)s
|
|
38
|
+
}
|
|
40
39
|
|
|
41
|
-
def algorithms():
|
|
42
|
-
if cext_available:
|
|
43
|
-
return Stemmer.language()
|
|
44
|
-
else:
|
|
40
|
+
def algorithms():
|
|
45
41
|
return list(_languages.keys())
|
|
46
42
|
|
|
47
|
-
def stemmer(lang):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
raise KeyError("Stemming algorithm '%%s' not found" %% lang)
|
|
43
|
+
def stemmer(lang):
|
|
44
|
+
lang = lang.lower()
|
|
45
|
+
if lang in _languages:
|
|
46
|
+
return _languages[lang]()
|
|
47
|
+
else:
|
|
48
|
+
raise KeyError("Stemming algorithm '%%s' not found" %% lang)
|
|
54
49
|
''' % {'imports': '\n'.join(imports), 'languages': '\n'.join(languages)}
|
|
55
50
|
|
|
56
51
|
with open(os.path.join(python_out_folder, '__init__.py'), 'w') as out:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from setuptools import setup
|
|
4
4
|
import re
|
|
5
5
|
|
|
6
|
-
SNOWBALL_VERSION = '3.
|
|
6
|
+
SNOWBALL_VERSION = '3.1.1'
|
|
7
7
|
|
|
8
8
|
n_stemmers = 0
|
|
9
9
|
|
|
@@ -36,21 +36,18 @@ desc = 'This package provides ' + str(n_stemmers) + ' stemmers for ' + \
|
|
|
36
36
|
classifiers = [
|
|
37
37
|
'Development Status :: 5 - Production/Stable',
|
|
38
38
|
'Intended Audience :: Developers',
|
|
39
|
-
'License :: OSI Approved :: BSD License'
|
|
40
39
|
]
|
|
41
40
|
|
|
42
41
|
for lang in langs:
|
|
43
42
|
lang_titlecase = lang.title()
|
|
44
43
|
# Only classifiers listed in https://pypi.org/classifiers/ are allowed
|
|
45
44
|
# Remove them here or submit them to https://github.com/pypa/trove-classifiers
|
|
46
|
-
|
|
45
|
+
if lang_titlecase != 'Sesotho':
|
|
46
|
+
classifiers.append('Natural Language :: ' + lang_titlecase)
|
|
47
47
|
|
|
48
48
|
classifiers.extend([
|
|
49
49
|
'Operating System :: OS Independent',
|
|
50
50
|
'Programming Language :: Python',
|
|
51
|
-
'Programming Language :: Python :: 2',
|
|
52
|
-
'Programming Language :: Python :: 2.6',
|
|
53
|
-
'Programming Language :: Python :: 2.7',
|
|
54
51
|
'Programming Language :: Python :: 3',
|
|
55
52
|
'Programming Language :: Python :: 3.3',
|
|
56
53
|
'Programming Language :: Python :: 3.4',
|
|
@@ -63,6 +60,7 @@ classifiers.extend([
|
|
|
63
60
|
'Programming Language :: Python :: 3.11',
|
|
64
61
|
'Programming Language :: Python :: 3.12',
|
|
65
62
|
'Programming Language :: Python :: 3.13',
|
|
63
|
+
'Programming Language :: Python :: 3.14',
|
|
66
64
|
'Programming Language :: Python :: Implementation :: CPython',
|
|
67
65
|
'Programming Language :: Python :: Implementation :: PyPy',
|
|
68
66
|
'Topic :: Database',
|
|
@@ -81,6 +79,6 @@ setup(name='snowballstemmer',
|
|
|
81
79
|
license="BSD-3-Clause",
|
|
82
80
|
packages=['snowballstemmer'],
|
|
83
81
|
package_dir={"snowballstemmer": "src/snowballstemmer"},
|
|
84
|
-
python_requires='
|
|
82
|
+
python_requires='>=3.3',
|
|
85
83
|
classifiers = classifiers
|
|
86
84
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class BaseStemmer
|
|
1
|
+
class BaseStemmer:
|
|
2
2
|
def __init__(self):
|
|
3
3
|
self.set_current("")
|
|
4
4
|
|
|
@@ -88,20 +88,16 @@ class BaseStemmer(object):
|
|
|
88
88
|
return False
|
|
89
89
|
|
|
90
90
|
def eq_s(self, s):
|
|
91
|
-
if self.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.cursor += len(s)
|
|
96
|
-
return True
|
|
91
|
+
if self.current.startswith(s, self.cursor, self.limit):
|
|
92
|
+
self.cursor += len(s)
|
|
93
|
+
return True
|
|
94
|
+
return False
|
|
97
95
|
|
|
98
96
|
def eq_s_b(self, s):
|
|
99
|
-
if self.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
self.cursor -= len(s)
|
|
104
|
-
return True
|
|
97
|
+
if self.current.endswith(s, self.limit_backward, self.cursor):
|
|
98
|
+
self.cursor -= len(s)
|
|
99
|
+
return True
|
|
100
|
+
return False
|
|
105
101
|
|
|
106
102
|
def find_among(self, v):
|
|
107
103
|
i = 0
|
|
@@ -151,9 +147,8 @@ class BaseStemmer(object):
|
|
|
151
147
|
self.cursor = c + len(w.s)
|
|
152
148
|
if w.method is None:
|
|
153
149
|
return w.result
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if res:
|
|
150
|
+
if w.method(self):
|
|
151
|
+
self.cursor = c + len(w.s)
|
|
157
152
|
return w.result
|
|
158
153
|
i = w.substring_i
|
|
159
154
|
if i < 0:
|
|
@@ -208,9 +203,8 @@ class BaseStemmer(object):
|
|
|
208
203
|
self.cursor = c - len(w.s)
|
|
209
204
|
if w.method is None:
|
|
210
205
|
return w.result
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if res:
|
|
206
|
+
if w.method(self):
|
|
207
|
+
self.cursor = c - len(w.s)
|
|
214
208
|
return w.result
|
|
215
209
|
i = w.substring_i
|
|
216
210
|
if i < 0:
|
|
@@ -235,20 +229,16 @@ class BaseStemmer(object):
|
|
|
235
229
|
self.cursor = c_bra
|
|
236
230
|
return adjustment
|
|
237
231
|
|
|
238
|
-
def slice_check(self):
|
|
239
|
-
if self.bra < 0 or self.bra > self.ket or self.ket > self.limit or self.limit > len(self.current):
|
|
240
|
-
return False
|
|
241
|
-
return True
|
|
242
|
-
|
|
243
232
|
def slice_from(self, s):
|
|
244
233
|
'''
|
|
245
234
|
@type s string
|
|
246
235
|
'''
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
236
|
+
assert self.bra >= 0
|
|
237
|
+
assert self.bra <= self.ket
|
|
238
|
+
assert self.ket <= self.limit
|
|
239
|
+
assert self.limit <= len(self.current)
|
|
240
|
+
self.replace_s(self.bra, self.ket, s)
|
|
241
|
+
self.ket = self.bra + len(s)
|
|
252
242
|
|
|
253
243
|
def slice_del(self):
|
|
254
244
|
return self.slice_from("")
|
|
@@ -269,10 +259,11 @@ class BaseStemmer(object):
|
|
|
269
259
|
'''
|
|
270
260
|
Return the slice as a string.
|
|
271
261
|
'''
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
262
|
+
assert self.bra >= 0
|
|
263
|
+
assert self.bra <= self.ket
|
|
264
|
+
assert self.ket <= self.limit
|
|
265
|
+
assert self.limit <= len(self.current)
|
|
266
|
+
return self.current[self.bra:self.ket]
|
|
276
267
|
|
|
277
268
|
def assign_to(self):
|
|
278
269
|
'''
|