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