JOOMLA中国
  • Joomla中国首页
  • 社区
  • 教程
  • 应用市场
  • B计划
Joomla! Framework TM
  • Namespace
  • Class
  • Tree
  • Deprecated

Namespaces

  • Composer
    • Autoload
  • Joomla
    • Application
      • Cli
        • Output
          • Processor
      • Web
    • Data
    • DI
      • Exception
    • Event
    • Filter
    • Input
    • Ldap
    • Registry
      • Format
    • Session
      • Storage
    • String
    • Uri
    • Utilities
  • None
  • PasswordCompat
    • binary
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Yaml
        • Exception
    • Polyfill
      • Util

Classes

  • Inflector
  • Normalise
  • String
  • StringHelper
  1 <?php
  2 /**
  3  * Part of the Joomla Framework String Package
  4  *
  5  * @copyright  Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
  6  * @license    GNU General Public License version 2 or later; see LICENSE
  7  */
  8 
  9 namespace Joomla\String;
 10 
 11 use InvalidArgumentException;
 12 
 13 /**
 14  * Joomla Framework String Inflector Class
 15  *
 16  * The Inflector transforms words
 17  *
 18  * @since  1.0
 19  */
 20 class Inflector
 21 {
 22     /**
 23      * The singleton instance.
 24      *
 25      * @var    Inflector
 26      * @since  1.0
 27      */
 28     private static $instance;
 29 
 30     /**
 31      * The inflector rules for singularisation, pluralisation and countability.
 32      *
 33      * @var    array
 34      * @since  1.0
 35      */
 36     private $rules = array(
 37         'singular' => array(
 38             '/(matr)ices$/i' => '\1ix',
 39             '/(vert|ind)ices$/i' => '\1ex',
 40             '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
 41             '/([ftw]ax)es/i' => '\1',
 42             '/(cris|ax|test)es$/i' => '\1is',
 43             '/(shoe|slave)s$/i' => '\1',
 44             '/(o)es$/i' => '\1',
 45             '/([^aeiouy]|qu)ies$/i' => '\1y',
 46             '/$1ses$/i' => '\s',
 47             '/ses$/i' => '\s',
 48             '/eaus$/' => 'eau',
 49             '/^(.*us)$/' => '\\1',
 50             '/s$/i' => '',
 51         ),
 52         'plural' => array(
 53             '/([m|l])ouse$/i' => '\1ice',
 54             '/(matr|vert|ind)(ix|ex)$/i'  => '\1ices',
 55             '/(x|ch|ss|sh)$/i' => '\1es',
 56             '/([^aeiouy]|qu)y$/i' => '\1ies',
 57             '/([^aeiouy]|qu)ies$/i' => '\1y',
 58             '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
 59             '/sis$/i' => 'ses',
 60             '/([ti])um$/i' => '\1a',
 61             '/(buffal|tomat)o$/i' => '\1\2oes',
 62             '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
 63             '/us$/i' => 'uses',
 64             '/(ax|cris|test)is$/i' => '\1es',
 65             '/s$/i' => 's',
 66             '/$/' => 's',
 67         ),
 68         'countable' => array(
 69             'id',
 70             'hits',
 71             'clicks',
 72         ),
 73     );
 74 
 75     /**
 76      * Cached inflections.
 77      *
 78      * The array is in the form [singular => plural]
 79      *
 80      * @var    array
 81      * @since  1.0
 82      */
 83     private $cache = array();
 84 
 85     /**
 86      * Protected constructor.
 87      *
 88      * @since  1.0
 89      */
 90     protected function __construct()
 91     {
 92         // Pre=populate the irregual singular/plural.
 93         $this
 94             ->addWord('deer')
 95             ->addWord('moose')
 96             ->addWord('sheep')
 97             ->addWord('bison')
 98             ->addWord('salmon')
 99             ->addWord('pike')
100             ->addWord('trout')
101             ->addWord('fish')
102             ->addWord('swine')
103 
104             ->addWord('alias', 'aliases')
105             ->addWord('bus', 'buses')
106             ->addWord('foot', 'feet')
107             ->addWord('goose', 'geese')
108             ->addWord('hive', 'hives')
109             ->addWord('louse', 'lice')
110             ->addWord('man', 'men')
111             ->addWord('mouse', 'mice')
112             ->addWord('ox', 'oxen')
113             ->addWord('quiz', 'quizes')
114             ->addWord('status', 'statuses')
115             ->addWord('tooth', 'teeth')
116             ->addWord('woman', 'women');
117     }
118 
119     /**
120      * Adds inflection regex rules to the inflector.
121      *
122      * @param   mixed   $data      A string or an array of strings or regex rules to add.
123      * @param   string  $ruleType  The rule type: singular | plural | countable
124      *
125      * @return  void
126      *
127      * @since   1.0
128      * @throws  InvalidArgumentException
129      */
130     private function addRule($data, $ruleType)
131     {
132         if (is_string($data))
133         {
134             $data = array($data);
135         }
136         elseif (!is_array($data))
137         {
138             // Do not translate.
139             throw new InvalidArgumentException('Invalid inflector rule data.');
140         }
141 
142         foreach ($data as $rule)
143         {
144             // Ensure a string is pushed.
145             array_push($this->rules[$ruleType], (string) $rule);
146         }
147     }
148 
149     /**
150      * Gets an inflected word from the cache where the singular form is supplied.
151      *
152      * @param   string  $singular  A singular form of a word.
153      *
154      * @return  mixed  The cached inflection or false if none found.
155      *
156      * @since   1.0
157      */
158     private function getCachedPlural($singular)
159     {
160         $singular = StringHelper::strtolower($singular);
161 
162         // Check if the word is in cache.
163         if (isset($this->cache[$singular]))
164         {
165             return $this->cache[$singular];
166         }
167 
168         return false;
169     }
170 
171     /**
172      * Gets an inflected word from the cache where the plural form is supplied.
173      *
174      * @param   string  $plural  A plural form of a word.
175      *
176      * @return  mixed  The cached inflection or false if none found.
177      *
178      * @since   1.0
179      */
180     private function getCachedSingular($plural)
181     {
182         $plural = StringHelper::strtolower($plural);
183 
184         return array_search($plural, $this->cache);
185     }
186 
187     /**
188      * Execute a regex from rules.
189      *
190      * The 'plural' rule type expects a singular word.
191      * The 'singular' rule type expects a plural word.
192      *
193      * @param   string  $word      The string input.
194      * @param   string  $ruleType  String (eg, singular|plural)
195      *
196      * @return  mixed  An inflected string, or false if no rule could be applied.
197      *
198      * @since   1.0
199      */
200     private function matchRegexRule($word, $ruleType)
201     {
202         // Cycle through the regex rules.
203         foreach ($this->rules[$ruleType] as $regex => $replacement)
204         {
205             $matches = 0;
206             $matchedWord = preg_replace($regex, $replacement, $word, -1, $matches);
207 
208             if ($matches > 0)
209             {
210                 return $matchedWord;
211             }
212         }
213 
214         return false;
215     }
216 
217     /**
218      * Sets an inflected word in the cache.
219      *
220      * @param   string  $singular  The singular form of the word.
221      * @param   string  $plural    The plural form of the word. If omitted, it is assumed the singular and plural are identical.
222      *
223      * @return  void
224      *
225      * @since   1.0
226      */
227     private function setCache($singular, $plural = null)
228     {
229         $singular = StringHelper::strtolower($singular);
230 
231         if ($plural === null)
232         {
233             $plural = $singular;
234         }
235         else
236         {
237             $plural = StringHelper::strtolower($plural);
238         }
239 
240         $this->cache[$singular] = $plural;
241     }
242 
243     /**
244      * Adds a countable word.
245      *
246      * @param   mixed  $data  A string or an array of strings to add.
247      *
248      * @return  Inflector  Returns this object to support chaining.
249      *
250      * @since   1.0
251      */
252     public function addCountableRule($data)
253     {
254         $this->addRule($data, 'countable');
255 
256         return $this;
257     }
258 
259     /**
260      * Adds a specific singular-plural pair for a word.
261      *
262      * @param   string  $singular  The singular form of the word.
263      * @param   string  $plural    The plural form of the word. If omitted, it is assumed the singular and plural are identical.
264      *
265      * @return  Inflector  Returns this object to support chaining.
266      *
267      * @since   1.0
268      */
269     public function addWord($singular, $plural =null)
270     {
271         $this->setCache($singular, $plural);
272 
273         return $this;
274     }
275 
276     /**
277      * Adds a pluralisation rule.
278      *
279      * @param   mixed  $data  A string or an array of regex rules to add.
280      *
281      * @return  Inflector  Returns this object to support chaining.
282      *
283      * @since   1.0
284      */
285     public function addPluraliseRule($data)
286     {
287         $this->addRule($data, 'plural');
288 
289         return $this;
290     }
291 
292     /**
293      * Adds a singularisation rule.
294      *
295      * @param   mixed  $data  A string or an array of regex rules to add.
296      *
297      * @return  Inflector  Returns this object to support chaining.
298      *
299      * @since   1.0
300      */
301     public function addSingulariseRule($data)
302     {
303         $this->addRule($data, 'singular');
304 
305         return $this;
306     }
307 
308     /**
309      * Gets an instance of the JStringInflector singleton.
310      *
311      * @param   boolean  $new  If true (default is false), returns a new instance regardless if one exists.
312      *                         This argument is mainly used for testing.
313      *
314      * @return  Inflector
315      *
316      * @since   1.0
317      */
318     public static function getInstance($new = false)
319     {
320         if ($new)
321         {
322             return new static;
323         }
324         elseif (!is_object(self::$instance))
325         {
326             self::$instance = new static;
327         }
328 
329         return self::$instance;
330     }
331 
332     /**
333      * Checks if a word is countable.
334      *
335      * @param   string  $word  The string input.
336      *
337      * @return  boolean  True if word is countable, false otherwise.
338      *
339      * @since   1.0
340      */
341     public function isCountable($word)
342     {
343         return (boolean) in_array($word, $this->rules['countable']);
344     }
345 
346     /**
347      * Checks if a word is in a plural form.
348      *
349      * @param   string  $word  The string input.
350      *
351      * @return  boolean  True if word is plural, false if not.
352      *
353      * @since   1.0
354      */
355     public function isPlural($word)
356     {
357         // Try the cache for an known inflection.
358         $inflection = $this->getCachedSingular($word);
359 
360         if ($inflection !== false)
361         {
362             return true;
363         }
364 
365         $singularWord = $this->toSingular($word);
366 
367         if ($singularWord === false)
368         {
369             return false;
370         }
371 
372         // Compute the inflection to cache the values, and compare.
373         return $this->toPlural($singularWord) == $word;
374     }
375 
376     /**
377      * Checks if a word is in a singular form.
378      *
379      * @param   string  $word  The string input.
380      *
381      * @return  boolean  True if word is singular, false if not.
382      *
383      * @since   1.0
384      */
385     public function isSingular($word)
386     {
387         // Try the cache for an known inflection.
388         $inflection = $this->getCachedPlural($word);
389 
390         if ($inflection !== false)
391         {
392             return true;
393         }
394 
395         $pluralWord = $this->toPlural($word);
396 
397         if ($pluralWord === false)
398         {
399             return false;
400         }
401 
402         // Compute the inflection to cache the values, and compare.
403         return $this->toSingular($pluralWord) == $word;
404     }
405 
406     /**
407      * Converts a word into its plural form.
408      *
409      * @param   string  $word  The singular word to pluralise.
410      *
411      * @return  mixed  An inflected string, or false if no rule could be applied.
412      *
413      * @since   1.0
414      */
415     public function toPlural($word)
416     {
417         // Try to get the cached plural form from the singular.
418         $cache = $this->getCachedPlural($word);
419 
420         if ($cache !== false)
421         {
422             return $cache;
423         }
424 
425         // Check if the word is a known singular.
426         if ($this->getCachedSingular($word))
427         {
428             return false;
429         }
430 
431         // Compute the inflection.
432         $inflected = $this->matchRegexRule($word, 'plural');
433 
434         if ($inflected !== false)
435         {
436             $this->setCache($word, $inflected);
437 
438             return $inflected;
439         }
440 
441         // Dead code
442         return false;
443     }
444 
445     /**
446      * Converts a word into its singular form.
447      *
448      * @param   string  $word  The plural word to singularise.
449      *
450      * @return  mixed  An inflected string, or false if no rule could be applied.
451      *
452      * @since   1.0
453      */
454     public function toSingular($word)
455     {
456         // Try to get the cached singular form from the plural.
457         $cache = $this->getCachedSingular($word);
458 
459         if ($cache !== false)
460         {
461             return $cache;
462         }
463 
464         // Check if the word is a known plural.
465         if ($this->getCachedPlural($word))
466         {
467             return false;
468         }
469 
470         // Compute the inflection.
471         $inflected = $this->matchRegexRule($word, 'singular');
472 
473         if ($inflected !== false)
474         {
475             $this->setCache($inflected, $word);
476 
477             return $inflected;
478         }
479 
480         return false;
481     }
482 }
483 
Joomla! Framework TM API documentation generated by ApiGen 2.8.0
Joomla!® and Joomla! Framework™ are trademarks of Open Source Matters, Inc. in the United States and other countries.