PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.14.6
Independent Analytics – WordPress Analytics Plugin v2.14.6
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 1 year ago FrenchInflector.php 2 years ago InflectorInterface.php 2 years ago
EnglishInflector.php
424 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 IAWPSCOPED\Symfony\Component\String\Inflector;
12
13 /** @internal */
14 final class EnglishInflector implements InflectorInterface
15 {
16 /**
17 * Map English plural to singular suffixes.
18 *
19 * @see http://english-zone.com/spelling/plurals.html
20 */
21 private const PLURAL_MAP = [
22 // First entry: plural suffix, reversed
23 // Second entry: length of plural suffix
24 // Third entry: Whether the suffix may succeed a vowel
25 // Fourth entry: Whether the suffix may succeed a consonant
26 // Fifth entry: singular suffix, normal
27 // bacteria (bacterium)
28 ['airetcab', 8, \true, \true, 'bacterium'],
29 // corpora (corpus)
30 ['aroproc', 7, \true, \true, 'corpus'],
31 // criteria (criterion)
32 ['airetirc', 8, \true, \true, 'criterion'],
33 // curricula (curriculum)
34 ['alucirruc', 9, \true, \true, 'curriculum'],
35 // genera (genus)
36 ['areneg', 6, \true, \true, 'genus'],
37 // media (medium)
38 ['aidem', 5, \true, \true, 'medium'],
39 // memoranda (memorandum)
40 ['adnaromem', 9, \true, \true, 'memorandum'],
41 // phenomena (phenomenon)
42 ['anemonehp', 9, \true, \true, 'phenomenon'],
43 // strata (stratum)
44 ['atarts', 6, \true, \true, 'stratum'],
45 // nebulae (nebula)
46 ['ea', 2, \true, \true, 'a'],
47 // services (service)
48 ['secivres', 8, \true, \true, 'service'],
49 // mice (mouse), lice (louse)
50 ['eci', 3, \false, \true, 'ouse'],
51 // geese (goose)
52 ['esee', 4, \false, \true, 'oose'],
53 // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
54 ['i', 1, \true, \true, 'us'],
55 // men (man), women (woman)
56 ['nem', 3, \true, \true, 'man'],
57 // children (child)
58 ['nerdlihc', 8, \true, \true, 'child'],
59 // oxen (ox)
60 ['nexo', 4, \false, \false, 'ox'],
61 // indices (index), appendices (appendix), prices (price)
62 ['seci', 4, \false, \true, ['ex', 'ix', 'ice']],
63 // codes (code)
64 ['sedoc', 5, \false, \true, 'code'],
65 // selfies (selfie)
66 ['seifles', 7, \true, \true, 'selfie'],
67 // zombies (zombie)
68 ['seibmoz', 7, \true, \true, 'zombie'],
69 // movies (movie)
70 ['seivom', 6, \true, \true, 'movie'],
71 // names (name)
72 ['seman', 5, \true, \false, 'name'],
73 // conspectuses (conspectus), prospectuses (prospectus)
74 ['sesutcep', 8, \true, \true, 'pectus'],
75 // feet (foot)
76 ['teef', 4, \true, \true, 'foot'],
77 // geese (goose)
78 ['eseeg', 5, \true, \true, 'goose'],
79 // teeth (tooth)
80 ['hteet', 5, \true, \true, 'tooth'],
81 // news (news)
82 ['swen', 4, \true, \true, 'news'],
83 // series (series)
84 ['seires', 6, \true, \true, 'series'],
85 // babies (baby)
86 ['sei', 3, \false, \true, 'y'],
87 // accesses (access), addresses (address), kisses (kiss)
88 ['sess', 4, \true, \false, 'ss'],
89 // statuses (status)
90 ['sesutats', 8, \true, \true, 'status'],
91 // article (articles), ancle (ancles)
92 ['sel', 3, \true, \true, 'le'],
93 // analyses (analysis), ellipses (ellipsis), fungi (fungus),
94 // neuroses (neurosis), theses (thesis), emphases (emphasis),
95 // oases (oasis), crises (crisis), houses (house), bases (base),
96 // atlases (atlas)
97 ['ses', 3, \true, \true, ['s', 'se', 'sis']],
98 // objectives (objective), alternative (alternatives)
99 ['sevit', 5, \true, \true, 'tive'],
100 // drives (drive)
101 ['sevird', 6, \false, \true, 'drive'],
102 // lives (life), wives (wife)
103 ['sevi', 4, \false, \true, 'ife'],
104 // moves (move)
105 ['sevom', 5, \true, \true, 'move'],
106 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff)
107 ['sev', 3, \true, \true, ['f', 've', 'ff']],
108 // axes (axis), axes (ax), axes (axe)
109 ['sexa', 4, \false, \false, ['ax', 'axe', 'axis']],
110 // indexes (index), matrixes (matrix)
111 ['sex', 3, \true, \false, 'x'],
112 // quizzes (quiz)
113 ['sezz', 4, \true, \false, 'z'],
114 // bureaus (bureau)
115 ['suae', 4, \false, \true, 'eau'],
116 // fees (fee), trees (tree), employees (employee)
117 ['see', 3, \true, \true, 'ee'],
118 // edges (edge)
119 ['segd', 4, \true, \true, 'dge'],
120 // roses (rose), garages (garage), cassettes (cassette),
121 // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
122 // shoes (shoe)
123 ['se', 2, \true, \true, ['', 'e']],
124 // status (status)
125 ['sutats', 6, \true, \true, 'status'],
126 // tags (tag)
127 ['s', 1, \true, \true, ''],
128 // chateaux (chateau)
129 ['xuae', 4, \false, \true, 'eau'],
130 // people (person)
131 ['elpoep', 6, \true, \true, 'person'],
132 ];
133 /**
134 * Map English singular to plural suffixes.
135 *
136 * @see http://english-zone.com/spelling/plurals.html
137 */
138 private const SINGULAR_MAP = [
139 // First entry: singular suffix, reversed
140 // Second entry: length of singular suffix
141 // Third entry: Whether the suffix may succeed a vowel
142 // Fourth entry: Whether the suffix may succeed a consonant
143 // Fifth entry: plural suffix, normal
144 // axes (axis)
145 ['sixa', 4, \false, \false, 'axes'],
146 // criterion (criteria)
147 ['airetirc', 8, \false, \false, 'criterion'],
148 // nebulae (nebula)
149 ['aluben', 6, \false, \false, 'nebulae'],
150 // children (child)
151 ['dlihc', 5, \true, \true, 'children'],
152 // prices (price)
153 ['eci', 3, \false, \true, 'ices'],
154 // services (service)
155 ['ecivres', 7, \true, \true, 'services'],
156 // lives (life), wives (wife)
157 ['efi', 3, \false, \true, 'ives'],
158 // selfies (selfie)
159 ['eifles', 6, \true, \true, 'selfies'],
160 // movies (movie)
161 ['eivom', 5, \true, \true, 'movies'],
162 // lice (louse)
163 ['esuol', 5, \false, \true, 'lice'],
164 // mice (mouse)
165 ['esuom', 5, \false, \true, 'mice'],
166 // geese (goose)
167 ['esoo', 4, \false, \true, 'eese'],
168 // houses (house), bases (base)
169 ['es', 2, \true, \true, 'ses'],
170 // geese (goose)
171 ['esoog', 5, \true, \true, 'geese'],
172 // caves (cave)
173 ['ev', 2, \true, \true, 'ves'],
174 // drives (drive)
175 ['evird', 5, \false, \true, 'drives'],
176 // objectives (objective), alternative (alternatives)
177 ['evit', 4, \true, \true, 'tives'],
178 // moves (move)
179 ['evom', 4, \true, \true, 'moves'],
180 // staves (staff)
181 ['ffats', 5, \true, \true, 'staves'],
182 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
183 ['ff', 2, \true, \true, 'ffs'],
184 // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
185 ['f', 1, \true, \true, ['fs', 'ves']],
186 // arches (arch)
187 ['hc', 2, \true, \true, 'ches'],
188 // bushes (bush)
189 ['hs', 2, \true, \true, 'shes'],
190 // teeth (tooth)
191 ['htoot', 5, \true, \true, 'teeth'],
192 // albums (album)
193 ['mubla', 5, \true, \true, 'albums'],
194 // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum)
195 ['mu', 2, \true, \true, 'a'],
196 // men (man), women (woman)
197 ['nam', 3, \true, \true, 'men'],
198 // people (person)
199 ['nosrep', 6, \true, \true, ['persons', 'people']],
200 // criteria (criterion)
201 ['noiretirc', 9, \true, \true, 'criteria'],
202 // phenomena (phenomenon)
203 ['nonemonehp', 10, \true, \true, 'phenomena'],
204 // echoes (echo)
205 ['ohce', 4, \true, \true, 'echoes'],
206 // heroes (hero)
207 ['oreh', 4, \true, \true, 'heroes'],
208 // atlases (atlas)
209 ['salta', 5, \true, \true, 'atlases'],
210 // aliases (alias)
211 ['saila', 5, \true, \true, 'aliases'],
212 // irises (iris)
213 ['siri', 4, \true, \true, 'irises'],
214 // analyses (analysis), ellipses (ellipsis), neuroses (neurosis)
215 // theses (thesis), emphases (emphasis), oases (oasis),
216 // crises (crisis)
217 ['sis', 3, \true, \true, 'ses'],
218 // accesses (access), addresses (address), kisses (kiss)
219 ['ss', 2, \true, \false, 'sses'],
220 // syllabi (syllabus)
221 ['suballys', 8, \true, \true, 'syllabi'],
222 // buses (bus)
223 ['sub', 3, \true, \true, 'buses'],
224 // circuses (circus)
225 ['suc', 3, \true, \true, 'cuses'],
226 // hippocampi (hippocampus)
227 ['supmacoppih', 11, \false, \false, 'hippocampi'],
228 // campuses (campus)
229 ['sup', 3, \true, \true, 'puses'],
230 // status (status)
231 ['sutats', 6, \true, \true, ['status', 'statuses']],
232 // conspectuses (conspectus), prospectuses (prospectus)
233 ['sutcep', 6, \true, \true, 'pectuses'],
234 // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
235 ['su', 2, \true, \true, 'i'],
236 // news (news)
237 ['swen', 4, \true, \true, 'news'],
238 // feet (foot)
239 ['toof', 4, \true, \true, 'feet'],
240 // chateaux (chateau), bureaus (bureau)
241 ['uae', 3, \false, \true, ['eaus', 'eaux']],
242 // oxen (ox)
243 ['xo', 2, \false, \false, 'oxen'],
244 // hoaxes (hoax)
245 ['xaoh', 4, \true, \false, 'hoaxes'],
246 // indices (index)
247 ['xedni', 5, \false, \true, ['indicies', 'indexes']],
248 // boxes (box)
249 ['xo', 2, \false, \true, 'oxes'],
250 // indexes (index), matrixes (matrix)
251 ['x', 1, \true, \false, ['cies', 'xes']],
252 // appendices (appendix)
253 ['xi', 2, \false, \true, 'ices'],
254 // babies (baby)
255 ['y', 1, \false, \true, 'ies'],
256 // quizzes (quiz)
257 ['ziuq', 4, \true, \false, 'quizzes'],
258 // waltzes (waltz)
259 ['z', 1, \true, \true, 'zes'],
260 ];
261 /**
262 * A list of words which should not be inflected, reversed.
263 */
264 private const UNINFLECTED = [
265 '',
266 // data
267 'atad',
268 // deer
269 'reed',
270 // equipment
271 'tnempiuqe',
272 // feedback
273 'kcabdeef',
274 // fish
275 'hsif',
276 // health
277 'htlaeh',
278 // history
279 'yrotsih',
280 // info
281 'ofni',
282 // information
283 'noitamrofni',
284 // money
285 'yenom',
286 // moose
287 'esoom',
288 // series
289 'seires',
290 // sheep
291 'peehs',
292 // species
293 'seiceps',
294 // traffic
295 'ciffart',
296 // aircraft
297 'tfarcria',
298 // hardware
299 'erawdrah',
300 ];
301 public function singularize(string $plural) : array
302 {
303 $pluralRev = \strrev($plural);
304 $lowerPluralRev = \strtolower($pluralRev);
305 $pluralLength = \strlen($lowerPluralRev);
306 // Check if the word is one which is not inflected, return early if so
307 if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) {
308 return [$plural];
309 }
310 // The outer loop iterates over the entries of the plural table
311 // The inner loop $j iterates over the characters of the plural suffix
312 // in the plural table to compare them with the characters of the actual
313 // given plural suffix
314 foreach (self::PLURAL_MAP as $map) {
315 $suffix = $map[0];
316 $suffixLength = $map[1];
317 $j = 0;
318 // Compare characters in the plural table and of the suffix of the
319 // given plural one by one
320 while ($suffix[$j] === $lowerPluralRev[$j]) {
321 // Let $j point to the next character
322 ++$j;
323 // Successfully compared the last character
324 // Add an entry with the singular suffix to the singular array
325 if ($j === $suffixLength) {
326 // Is there any character preceding the suffix in the plural string?
327 if ($j < $pluralLength) {
328 $nextIsVowel = \str_contains('aeiou', $lowerPluralRev[$j]);
329 if (!$map[2] && $nextIsVowel) {
330 // suffix may not succeed a vowel but next char is one
331 break;
332 }
333 if (!$map[3] && !$nextIsVowel) {
334 // suffix may not succeed a consonant but next char is one
335 break;
336 }
337 }
338 $newBase = \substr($plural, 0, $pluralLength - $suffixLength);
339 $newSuffix = $map[4];
340 // Check whether the first character in the plural suffix
341 // is uppercased. If yes, uppercase the first character in
342 // the singular suffix too
343 $firstUpper = \ctype_upper($pluralRev[$j - 1]);
344 if (\is_array($newSuffix)) {
345 $singulars = [];
346 foreach ($newSuffix as $newSuffixEntry) {
347 $singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
348 }
349 return $singulars;
350 }
351 return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
352 }
353 // Suffix is longer than word
354 if ($j === $pluralLength) {
355 break;
356 }
357 }
358 }
359 // Assume that plural and singular is identical
360 return [$plural];
361 }
362 public function pluralize(string $singular) : array
363 {
364 $singularRev = \strrev($singular);
365 $lowerSingularRev = \strtolower($singularRev);
366 $singularLength = \strlen($lowerSingularRev);
367 // Check if the word is one which is not inflected, return early if so
368 if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) {
369 return [$singular];
370 }
371 // The outer loop iterates over the entries of the singular table
372 // The inner loop $j iterates over the characters of the singular suffix
373 // in the singular table to compare them with the characters of the actual
374 // given singular suffix
375 foreach (self::SINGULAR_MAP as $map) {
376 $suffix = $map[0];
377 $suffixLength = $map[1];
378 $j = 0;
379 // Compare characters in the singular table and of the suffix of the
380 // given plural one by one
381 while ($suffix[$j] === $lowerSingularRev[$j]) {
382 // Let $j point to the next character
383 ++$j;
384 // Successfully compared the last character
385 // Add an entry with the plural suffix to the plural array
386 if ($j === $suffixLength) {
387 // Is there any character preceding the suffix in the plural string?
388 if ($j < $singularLength) {
389 $nextIsVowel = \str_contains('aeiou', $lowerSingularRev[$j]);
390 if (!$map[2] && $nextIsVowel) {
391 // suffix may not succeed a vowel but next char is one
392 break;
393 }
394 if (!$map[3] && !$nextIsVowel) {
395 // suffix may not succeed a consonant but next char is one
396 break;
397 }
398 }
399 $newBase = \substr($singular, 0, $singularLength - $suffixLength);
400 $newSuffix = $map[4];
401 // Check whether the first character in the singular suffix
402 // is uppercased. If yes, uppercase the first character in
403 // the singular suffix too
404 $firstUpper = \ctype_upper($singularRev[$j - 1]);
405 if (\is_array($newSuffix)) {
406 $plurals = [];
407 foreach ($newSuffix as $newSuffixEntry) {
408 $plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
409 }
410 return $plurals;
411 }
412 return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
413 }
414 // Suffix is longer than word
415 if ($j === $singularLength) {
416 break;
417 }
418 }
419 }
420 // Assume that plural is singular with a trailing `s`
421 return [$singular . 's'];
422 }
423 }
424