Source for file inflector.php

Documentation is available at inflector.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  String
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Joomla Platform String Inflector Class
  14.  *
  15.  * The Inflector transforms words
  16.  *
  17.  * @package     Joomla.Platform
  18.  * @subpackage  String
  19.  * @since       12.1
  20.  */
  21. {
  22.     /**
  23.      * The singleton instance.
  24.      *
  25.      * @var    JStringInflector 
  26.      * @since  12.1
  27.      */
  28.     private static $_instance;
  29.  
  30.     /**
  31.      * The inflector rules for singularisation, pluralisation and countability.
  32.      *
  33.      * @var    array 
  34.      * @since  12.1
  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  12.1
  82.      */
  83.     private $_cache array();
  84.  
  85.     /**
  86.      * Protected constructor.
  87.      *
  88.      * @since  12.1
  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   12.1
  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   12.1
  157.      */
  158.     private function _getCachedPlural($singular)
  159.     {
  160.         $singular JString::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   12.1
  179.      */
  180.     private function _getCachedSingular($plural)
  181.     {
  182.         $plural JString::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   12.1
  199.      */
  200.     private function _matchRegexRule($word$ruleType)
  201.     {
  202.         // Cycle through the regex rules.
  203.         foreach ($this->_rules[$ruleTypeas $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   12.1
  226.      */
  227.     private function _setCache($singular$plural null)
  228.     {
  229.         $singular JString::strtolower($singular);
  230.  
  231.         if ($plural === null)
  232.         {
  233.             $plural $singular;
  234.         }
  235.         else
  236.         {
  237.             $plural JString::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  JStringInflector  Returns this object to support chaining.
  249.      *
  250.      * @since   12.1
  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  JStringInflector  Returns this object to support chaining.
  266.      *
  267.      * @since   12.1
  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  JStringInflector  Returns this object to support chaining.
  282.      *
  283.      * @since   12.1
  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  JStringInflector  Returns this object to support chaining.
  298.      *
  299.      * @since   12.1
  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  JStringInflector 
  315.      *
  316.      * @since   12.1
  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  12.1
  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  12.1
  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.         // Compute the inflection to cache the values, and compare.
  366.         return $this->toPlural($this->toSingular($word)) == $word;
  367.     }
  368.  
  369.     /**
  370.      * Checks if a word is in a singular form.
  371.      *
  372.      * @param   string  $word  The string input.
  373.      *
  374.      * @return  boolean  True if word is singular, false if not.
  375.      *
  376.      * @since  12.1
  377.      */
  378.     public function isSingular($word)
  379.     {
  380.         // Try the cache for an known inflection.
  381.         $inflection $this->_getCachedPlural($word);
  382.  
  383.         if ($inflection !== false)
  384.         {
  385.             return true;
  386.         }
  387.  
  388.         // Compute the inflection to cache the values, and compare.
  389.         return $this->toSingular($this->toPlural($word)) == $word;
  390.     }
  391.  
  392.     /**
  393.      * Converts a word into its plural form.
  394.      *
  395.      * @param   string  $word  The singular word to pluralise.
  396.      *
  397.      * @return  mixed  An inflected string, or false if no rule could be applied.
  398.      *
  399.      * @since  12.1
  400.      */
  401.     public function toPlural($word)
  402.     {
  403.         // Try to get the cached plural form from the singular.
  404.         $cache $this->_getCachedPlural($word);
  405.  
  406.         if ($cache !== false)
  407.         {
  408.             return $cache;
  409.         }
  410.  
  411.         // Check if the word is a known singular.
  412.         if ($this->_getCachedSingular($word))
  413.         {
  414.             return false;
  415.         }
  416.  
  417.         // Compute the inflection.
  418.         $inflected $this->_matchRegexRule($word'plural');
  419.  
  420.         if ($inflected !== false)
  421.         {
  422.             $this->_setCache($word$inflected);
  423.  
  424.             return $inflected;
  425.         }
  426.  
  427.         return false;
  428.     }
  429.  
  430.     /**
  431.      * Converts a word into its singular form.
  432.      *
  433.      * @param   string  $word  The plural word to singularise.
  434.      *
  435.      * @return  mixed  An inflected string, or false if no rule could be applied.
  436.      *
  437.      * @since  12.1
  438.      */
  439.     public function toSingular($word)
  440.     {
  441.         // Try to get the cached singular form from the plural.
  442.         $cache $this->_getCachedSingular($word);
  443.  
  444.         if ($cache !== false)
  445.         {
  446.             return $cache;
  447.         }
  448.  
  449.         // Check if the word is a known plural.
  450.         if ($this->_getCachedPlural($word))
  451.         {
  452.             return false;
  453.         }
  454.  
  455.         // Compute the inflection.
  456.         $inflected $this->_matchRegexRule($word'singular');
  457.  
  458.         if ($inflected !== false)
  459.         {
  460.             $this->_setCache($inflected$word);
  461.  
  462.             return $inflected;
  463.         }
  464.  
  465.         return false;
  466.     }
  467. }

Documentation generated on Tue, 19 Nov 2013 15:05:32 +0100 by phpDocumentor 1.4.3