PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 1.25.1
Independent Analytics – WordPress Analytics Plugin v1.25.1
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / symfony / string / Inflector / EnglishInflector.php
independent-analytics / vendor / symfony / string / Inflector Last commit date
EnglishInflector.php 3 years ago FrenchInflector.php 3 years ago InflectorInterface.php 3 years ago
EnglishInflector.php
383 lines
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace IAWP_SCOPED\Symfony\Component\String\Inflector;
12
13 final class EnglishInflector implements InflectorInterface
14 {
15 /**
16 * Map English plural to singular suffixes.
17 *
18 * @see http://english-zone.com/spelling/plurals.html
19 */
20 private const PLURAL_MAP = [
21 // First entry: plural suffix, reversed
22 // Second entry: length of plural suffix
23 // Third entry: Whether the suffix may succeed a vocal
24 // Fourth entry: Whether the suffix may succeed a consonant
25 // Fifth entry: singular suffix, normal
26 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
27 ['a', 1, \true, \true, ['on', 'um']],
28 // nebulae (nebula)
29 ['ea', 2, \true, \true, 'a'],
30 // services (service)
31 ['secivres', 8, \true, \true, 'service'],
32 // mice (mouse), lice (louse)
33 ['eci', 3, \false, \true, 'ouse'],
34 // geese (goose)
35 ['esee', 4, \false, \true, 'oose'],
36 // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
37 ['i', 1, \true, \true, 'us'],
38 // men (man), women (woman)
39 ['nem', 3, \true, \true, 'man'],
40 // children (child)
41 ['nerdlihc', 8, \true, \true, 'child'],
42 // oxen (ox)
43 ['nexo', 4, \false, \false, 'ox'],
44 // indices (index), appendices (appendix), prices (price)
45 ['seci', 4, \false, \true, ['ex', 'ix', 'ice']],
46 // codes (code)
47 ['sedoc', 5, \false, \true, 'code'],
48 // selfies (selfie)
49 ['seifles', 7, \true, \true, 'selfie'],
50 // zombies (zombie)
51 ['seibmoz', 7, \true, \true, 'zombie'],
52 // movies (movie)
53 ['seivom', 6, \true, \true, 'movie'],
54 // names (name)
55 ['seman', 5, \true, \false, 'name'],
56 // conspectuses (conspectus), prospectuses (prospectus)
57 ['sesutcep', 8, \true, \true, 'pectus'],
58 // feet (foot)
59 ['teef', 4, \true, \true, 'foot'],
60 // geese (goose)
61 ['eseeg', 5, \true, \true, 'goose'],
62 // teeth (tooth)
63 ['hteet', 5, \true, \true, 'tooth'],
64 // news (news)
65 ['swen', 4, \true, \true, 'news'],
66 // series (series)
67 ['seires', 6, \true, \true, 'series'],
68 // babies (baby)
69 ['sei', 3, \false, \true, 'y'],
70 // accesses (access), addresses (address), kisses (kiss)
71 ['sess', 4, \true, \false, 'ss'],
72 // analyses (analysis), ellipses (ellipsis), fungi (fungus),
73 // neuroses (neurosis), theses (thesis), emphases (emphasis),
74 // oases (oasis), crises (crisis), houses (house), bases (base),
75 // atlases (atlas)
76 ['ses', 3, \true, \true, ['s', 'se', 'sis']],
77 // objectives (objective), alternative (alternatives)
78 ['sevit', 5, \true, \true, 'tive'],
79 // drives (drive)
80 ['sevird', 6, \false, \true, 'drive'],
81 // lives (life), wives (wife)
82 ['sevi', 4, \false, \true, 'ife'],
83 // moves (move)
84 ['sevom', 5, \true, \true, 'move'],
85 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff)
86 ['sev', 3, \true, \true, ['f', 've', 'ff']],
87 // axes (axis), axes (ax), axes (axe)
88 ['sexa', 4, \false, \false, ['ax', 'axe', 'axis']],
89 // indexes (index), matrixes (matrix)
90 ['sex', 3, \true, \false, 'x'],
91 // quizzes (quiz)
92 ['sezz', 4, \true, \false, 'z'],
93 // bureaus (bureau)
94 ['suae', 4, \false, \true, 'eau'],
95 // fees (fee), trees (tree), employees (employee)
96 ['see', 3, \true, \true, 'ee'],
97 // edges (edge)
98 ['segd', 4, \true, \true, 'dge'],
99 // roses (rose), garages (garage), cassettes (cassette),
100 // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
101 // shoes (shoe)
102 ['se', 2, \true, \true, ['', 'e']],
103 // tags (tag)
104 ['s', 1, \true, \true, ''],
105 // chateaux (chateau)
106 ['xuae', 4, \false, \true, 'eau'],
107 // people (person)
108 ['elpoep', 6, \true, \true, 'person'],
109 ];
110 /**
111 * Map English singular to plural suffixes.
112 *
113 * @see http://english-zone.com/spelling/plurals.html
114 */
115 private const SINGULAR_MAP = [
116 // First entry: singular suffix, reversed
117 // Second entry: length of singular suffix
118 // Third entry: Whether the suffix may succeed a vocal
119 // Fourth entry: Whether the suffix may succeed a consonant
120 // Fifth entry: plural suffix, normal
121 // criterion (criteria)
122 ['airetirc', 8, \false, \false, 'criterion'],
123 // nebulae (nebula)
124 ['aluben', 6, \false, \false, 'nebulae'],
125 // children (child)
126 ['dlihc', 5, \true, \true, 'children'],
127 // prices (price)
128 ['eci', 3, \false, \true, 'ices'],
129 // services (service)
130 ['ecivres', 7, \true, \true, 'services'],
131 // lives (life), wives (wife)
132 ['efi', 3, \false, \true, 'ives'],
133 // selfies (selfie)
134 ['eifles', 6, \true, \true, 'selfies'],
135 // movies (movie)
136 ['eivom', 5, \true, \true, 'movies'],
137 // lice (louse)
138 ['esuol', 5, \false, \true, 'lice'],
139 // mice (mouse)
140 ['esuom', 5, \false, \true, 'mice'],
141 // geese (goose)
142 ['esoo', 4, \false, \true, 'eese'],
143 // houses (house), bases (base)
144 ['es', 2, \true, \true, 'ses'],
145 // geese (goose)
146 ['esoog', 5, \true, \true, 'geese'],
147 // caves (cave)
148 ['ev', 2, \true, \true, 'ves'],
149 // drives (drive)
150 ['evird', 5, \false, \true, 'drives'],
151 // objectives (objective), alternative (alternatives)
152 ['evit', 4, \true, \true, 'tives'],
153 // moves (move)
154 ['evom', 4, \true, \true, 'moves'],
155 // staves (staff)
156 ['ffats', 5, \true, \true, 'staves'],
157 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
158 ['ff', 2, \true, \true, 'ffs'],
159 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
160 ['f', 1, \true, \true, ['fs', 'ves']],
161 // arches (arch)
162 ['hc', 2, \true, \true, 'ches'],
163 // bushes (bush)
164 ['hs', 2, \true, \true, 'shes'],
165 // teeth (tooth)
166 ['htoot', 5, \true, \true, 'teeth'],
167 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
168 ['mu', 2, \true, \true, 'a'],
169 // men (man), women (woman)
170 ['nam', 3, \true, \true, 'men'],
171 // people (person)
172 ['nosrep', 6, \true, \true, ['persons', 'people']],
173 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
174 ['noi', 3, \true, \true, 'ions'],
175 // coupon (coupons)
176 ['nop', 3, \true, \true, 'pons'],
177 // seasons (season), treasons (treason), poisons (poison), lessons (lesson)
178 ['nos', 3, \true, \true, 'sons'],
179 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
180 ['no', 2, \true, \true, 'a'],
181 // echoes (echo)
182 ['ohce', 4, \true, \true, 'echoes'],
183 // heroes (hero)
184 ['oreh', 4, \true, \true, 'heroes'],
185 // atlases (atlas)
186 ['salta', 5, \true, \true, 'atlases'],
187 // irises (iris)
188 ['siri', 4, \true, \true, 'irises'],
189 // analyses (analysis), ellipses (ellipsis), neuroses (neurosis)
190 // theses (thesis), emphases (emphasis), oases (oasis),
191 // crises (crisis)
192 ['sis', 3, \true, \true, 'ses'],
193 // accesses (access), addresses (address), kisses (kiss)
194 ['ss', 2, \true, \false, 'sses'],
195 // syllabi (syllabus)
196 ['suballys', 8, \true, \true, 'syllabi'],
197 // buses (bus)
198 ['sub', 3, \true, \true, 'buses'],
199 // circuses (circus)
200 ['suc', 3, \true, \true, 'cuses'],
201 // conspectuses (conspectus), prospectuses (prospectus)
202 ['sutcep', 6, \true, \true, 'pectuses'],
203 // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
204 ['su', 2, \true, \true, 'i'],
205 // news (news)
206 ['swen', 4, \true, \true, 'news'],
207 // feet (foot)
208 ['toof', 4, \true, \true, 'feet'],
209 // chateaux (chateau), bureaus (bureau)
210 ['uae', 3, \false, \true, ['eaus', 'eaux']],
211 // oxen (ox)
212 ['xo', 2, \false, \false, 'oxen'],
213 // hoaxes (hoax)
214 ['xaoh', 4, \true, \false, 'hoaxes'],
215 // indices (index)
216 ['xedni', 5, \false, \true, ['indicies', 'indexes']],
217 // boxes (box)
218 ['xo', 2, \false, \true, 'oxes'],
219 // indexes (index), matrixes (matrix)
220 ['x', 1, \true, \false, ['cies', 'xes']],
221 // appendices (appendix)
222 ['xi', 2, \false, \true, 'ices'],
223 // babies (baby)
224 ['y', 1, \false, \true, 'ies'],
225 // quizzes (quiz)
226 ['ziuq', 4, \true, \false, 'quizzes'],
227 // waltzes (waltz)
228 ['z', 1, \true, \true, 'zes'],
229 ];
230 /**
231 * A list of words which should not be inflected, reversed.
232 */
233 private const UNINFLECTED = [
234 '',
235 // data
236 'atad',
237 // deer
238 'reed',
239 // feedback
240 'kcabdeef',
241 // fish
242 'hsif',
243 // info
244 'ofni',
245 // moose
246 'esoom',
247 // series
248 'seires',
249 // sheep
250 'peehs',
251 // species
252 'seiceps',
253 ];
254 /**
255 * {@inheritdoc}
256 */
257 public function singularize(string $plural) : array
258 {
259 $pluralRev = \strrev($plural);
260 $lowerPluralRev = \strtolower($pluralRev);
261 $pluralLength = \strlen($lowerPluralRev);
262 // Check if the word is one which is not inflected, return early if so
263 if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) {
264 return [$plural];
265 }
266 // The outer loop iterates over the entries of the plural table
267 // The inner loop $j iterates over the characters of the plural suffix
268 // in the plural table to compare them with the characters of the actual
269 // given plural suffix
270 foreach (self::PLURAL_MAP as $map) {
271 $suffix = $map[0];
272 $suffixLength = $map[1];
273 $j = 0;
274 // Compare characters in the plural table and of the suffix of the
275 // given plural one by one
276 while ($suffix[$j] === $lowerPluralRev[$j]) {
277 // Let $j point to the next character
278 ++$j;
279 // Successfully compared the last character
280 // Add an entry with the singular suffix to the singular array
281 if ($j === $suffixLength) {
282 // Is there any character preceding the suffix in the plural string?
283 if ($j < $pluralLength) {
284 $nextIsVocal = \false !== \strpos('aeiou', $lowerPluralRev[$j]);
285 if (!$map[2] && $nextIsVocal) {
286 // suffix may not succeed a vocal but next char is one
287 break;
288 }
289 if (!$map[3] && !$nextIsVocal) {
290 // suffix may not succeed a consonant but next char is one
291 break;
292 }
293 }
294 $newBase = \substr($plural, 0, $pluralLength - $suffixLength);
295 $newSuffix = $map[4];
296 // Check whether the first character in the plural suffix
297 // is uppercased. If yes, uppercase the first character in
298 // the singular suffix too
299 $firstUpper = \ctype_upper($pluralRev[$j - 1]);
300 if (\is_array($newSuffix)) {
301 $singulars = [];
302 foreach ($newSuffix as $newSuffixEntry) {
303 $singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
304 }
305 return $singulars;
306 }
307 return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
308 }
309 // Suffix is longer than word
310 if ($j === $pluralLength) {
311 break;
312 }
313 }
314 }
315 // Assume that plural and singular is identical
316 return [$plural];
317 }
318 /**
319 * {@inheritdoc}
320 */
321 public function pluralize(string $singular) : array
322 {
323 $singularRev = \strrev($singular);
324 $lowerSingularRev = \strtolower($singularRev);
325 $singularLength = \strlen($lowerSingularRev);
326 // Check if the word is one which is not inflected, return early if so
327 if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) {
328 return [$singular];
329 }
330 // The outer loop iterates over the entries of the singular table
331 // The inner loop $j iterates over the characters of the singular suffix
332 // in the singular table to compare them with the characters of the actual
333 // given singular suffix
334 foreach (self::SINGULAR_MAP as $map) {
335 $suffix = $map[0];
336 $suffixLength = $map[1];
337 $j = 0;
338 // Compare characters in the singular table and of the suffix of the
339 // given plural one by one
340 while ($suffix[$j] === $lowerSingularRev[$j]) {
341 // Let $j point to the next character
342 ++$j;
343 // Successfully compared the last character
344 // Add an entry with the plural suffix to the plural array
345 if ($j === $suffixLength) {
346 // Is there any character preceding the suffix in the plural string?
347 if ($j < $singularLength) {
348 $nextIsVocal = \false !== \strpos('aeiou', $lowerSingularRev[$j]);
349 if (!$map[2] && $nextIsVocal) {
350 // suffix may not succeed a vocal but next char is one
351 break;
352 }
353 if (!$map[3] && !$nextIsVocal) {
354 // suffix may not succeed a consonant but next char is one
355 break;
356 }
357 }
358 $newBase = \substr($singular, 0, $singularLength - $suffixLength);
359 $newSuffix = $map[4];
360 // Check whether the first character in the singular suffix
361 // is uppercased. If yes, uppercase the first character in
362 // the singular suffix too
363 $firstUpper = \ctype_upper($singularRev[$j - 1]);
364 if (\is_array($newSuffix)) {
365 $plurals = [];
366 foreach ($newSuffix as $newSuffixEntry) {
367 $plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
368 }
369 return $plurals;
370 }
371 return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
372 }
373 // Suffix is longer than word
374 if ($j === $singularLength) {
375 break;
376 }
377 }
378 }
379 // Assume that plural is singular with a trailing `s`
380 return [$singular . 's'];
381 }
382 }
383