[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/symfony/string/Inflector/ -> EnglishInflector.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer