PHP Pluralize Method

Posted by paul on March 3, 2007.

I recently found myself wanting a rails-esque pluralize function like that found in the Rails Inflector class. After inspecting the Rails implementation, and playing around a bit, I was able to get a PHP version working as a Smarty variable modifier. Thank goodness for the rails version, I have no idea how I would go about listing all the various kinds of singular / plural nouns. Where would one go for a list of those kinds of things?


class MyClass extends Smarty 
{
    
    function __construct()
    {
        ...
        $this->register_modifier( "pluralize", array( $this, "pluralize" ) );
        $this->register_modifier( "conditionallyPluralize", array( $this, "conditionallyPluralize" ) );
    }
 
    function conditionallyPluralize( $string, $count )
    {
        if ( intval( $count ) > 1 )
            return MyClass::pluralize( $string );

        return $string; 
    }

    function pluralize( $string ) 
    {

        $plural = array(
            array( '/(quiz)$/i',               "$1zes"   ),
	    array( '/^(ox)$/i',                "$1en"    ),
	    array( '/([m|l])ouse$/i',          "$1ice"   ),
	    array( '/(matr|vert|ind)ix|ex$/i', "$1ices"  ),
	    array( '/(x|ch|ss|sh)$/i',         "$1es"    ),
	    array( '/([^aeiouy]|qu)y$/i',      "$1ies"   ),
	    array( '/([^aeiouy]|qu)ies$/i',    "$1y"     ),
    	    array( '/(hive)$/i',               "$1s"     ),
    	    array( '/(?:([^f])fe|([lr])f)$/i', "$1$2ves" ),
    	    array( '/sis$/i',                  "ses"     ),
    	    array( '/([ti])um$/i',             "$1a"     ),
    	    array( '/(buffal|tomat)o$/i',      "$1oes"   ),
            array( '/(bu)s$/i',                "$1ses"   ),
    	    array( '/(alias|status)$/i',       "$1es"    ),
    	    array( '/(octop|vir)us$/i',        "$1i"     ),
    	    array( '/(ax|test)is$/i',          "$1es"    ),
    	    array( '/s$/i',                    "s"       ),
    	    array( '/$/',                      "s"       )
        );

        $irregular = array(
	    array( 'move',   'moves'    ),
	    array( 'sex',    'sexes'    ),
	    array( 'child',  'children' ),
	    array( 'man',    'men'      ),
	    array( 'person', 'people'   )
        );

        $uncountable = array( 
	    'sheep', 
	    'fish',
	    'series',
	    'species',
	    'money',
	    'rice',
	    'information',
	    'equipment'
        );

        // save some time in the case that singular and plural are the same
        if ( in_array( strtolower( $string ), $uncountable ) )
	    return $string;

        // check for irregular singular forms
        foreach ( $irregular as $noun )
        {
	    if ( strtolower( $string ) == $noun[0] )
	        return $noun[1];
        }

        // check for matches using regular expressions
        foreach ( $plural as $pattern )
        {
	    if ( preg_match( $pattern[0], $string ) )
	        return preg_replace( $pattern[0], $pattern[1], $string );
        }
	
        return $string;
    }

}

Works like a charm!

EDIT: Sho Kuwamoto took this example and ran with it, creating a really robust and complete pluralization solution for PHP (and ActionScript!). Check out his improvements here.

Comments
  1. Mike Schinkel - March 18, 2008 @ 02:54:27 AM

    Nice! The other pluralize() solutions I found were severely lacking.

  2. Sho - December 17, 2007 @ 07:59:52 PM

    Hi Paul. Thanks for doing this. As it turns out, I needed more accurate pluralization for my project, so I tweaked the rules and added a singularizer as well. The code can be found here.

    Thanks again for doing this!

  3. Michael Wood - September 6, 2007 @ 01:24:59 AM

    Thanks! Works perfectly.

  4. Mike - August 5, 2007 @ 10:32:24 AM

    It's very beautifully

  5. Anonymous - July 17, 2007 @ 11:04:54 PM

    Thank you for the above snippet, it works great!

  6. The content of this field is kept private and will not be shown publicly.
    • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
    • Lines and paragraphs break automatically.

    More information about formatting options

    Captcha
    This question is used to make sure you are a human visitor and to prevent spam submissions.
    Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.