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