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