Welcome Guest, Not a member yet? Register   Sign In
Inflector Helper
#1

[eluser]alex-uk[/eluser]
Here is my updated inflector helper code.

It goes further than the original code and properly 'pluralifies' words based on English language rules (it doesn't just stick 's' or 'es' on the end!). There are some words that do not go by the rules - like cafe - and these will not work with it. Also it can not distinguish if a word is already a plural - so if you enter boats, you will get boatses out!

If you want me to explain further or add comments then let me know.

I hope this is useful to someone!

Alex


Code:
/**
* Plural
*
* Takes a singular word and makes it plural
*
* @access    public
* @param    string
* @param    bool
* @return    str
*/    
if ( ! function_exists('plural'))
{    
    function plural($str, $force = FALSE)
    {
        $str = strtolower(trim($str));
        if ( substr($str, -2) == 'sh'
            OR substr($str, -2) == 'ch'
            OR substr($str, -1) == 'x'
            OR substr($str, -1) == 'z'
            OR substr($str, -1) == 's' )
        {
            $str = $str . 'es';
        }
        elseif ( substr($str, -2) == 'wy'
            OR substr($str, -2) == 'ry'
            OR substr($str, -2) == 'ty'
            OR substr($str, -2) == 'py'
            OR substr($str, -2) == 'sy'
            OR substr($str, -2) == 'dy'
            OR substr($str, -2) == 'fy'
            OR substr($str, -2) == 'gy'
            OR substr($str, -2) == 'hy'
            OR substr($str, -2) == 'jy'
            OR substr($str, -2) == 'ky'
            OR substr($str, -2) == 'ly'
            OR substr($str, -2) == 'zy'
            OR substr($str, -2) == 'xy'
            OR substr($str, -2) == 'cy'
            OR substr($str, -2) == 'vy'
            OR substr($str, -2) == 'by'
            OR substr($str, -2) == 'ny'
            OR substr($str, -2) == 'my' )
        {
            $str = substr($str, 1) . 'ies';
        }
        elseif ( substr($str, -1) == 'f' )
        {
            $str = substr($str, 1) . 'ves';
        }
        elseif ( substr($str, -2) == 'fe' )
        {
            $str = substr($str, 2) . 'ves';
        }
        elseif ( substr($str, -2) == 'is' )
        {
            $str = substr($str, 2) . 'es';
        }
        else
        {
            $str = $str . 's';
        }
        return $str;
}
#2

[eluser]m4rw3r[/eluser]
substr() can take negative parameters, which would make your code much more readable:
Code:
$str = strrev($str);
if ( substr($str, 0, 2) == 'hs'
    OR substr($str, 0, 2) == 'hc'
// becomes
if(substr($str, -2) == 'sh'
    OR substr($str, -2) == 'ch'
If it has a negative start, it starts that many chars from the end. And if it has a negative end, it ends that many chars from the end.
#3

[eluser]sophistry[/eluser]
while you are on the subject of inflectors... (seems to be today's theme):

This one is interesting.

http://codeigniter.com/wiki/Inflector/
#4

[eluser]alex-uk[/eluser]
[quote author="m4rw3r" date="1229466048"]substr() can take negative parameters, which would make your code much more readable...[/quote]

Good point - why didn't I think of that?!?

Revised code:
Code:
if ( ! function_exists('plural'))
{    
    function plural($str, $force = FALSE)
    {
        $str = strtolower(trim($str));
        if ( substr($str, -2) == 'sh'
            OR substr($str, -2) == 'ch'
            OR substr($str, -1) == 'x'
            OR substr($str, -1) == 'z'
            OR substr($str, -1) == 's' )
        {
            $str = $str . 'es';
        }
        elseif ( substr($str, -2) == 'wy'
            OR substr($str, -2) == 'ry'
            OR substr($str, -2) == 'ty'
            OR substr($str, -2) == 'py'
            OR substr($str, -2) == 'sy'
            OR substr($str, -2) == 'dy'
            OR substr($str, -2) == 'fy'
            OR substr($str, -2) == 'gy'
            OR substr($str, -2) == 'hy'
            OR substr($str, -2) == 'jy'
            OR substr($str, -2) == 'ky'
            OR substr($str, -2) == 'ly'
            OR substr($str, -2) == 'zy'
            OR substr($str, -2) == 'xy'
            OR substr($str, -2) == 'cy'
            OR substr($str, -2) == 'vy'
            OR substr($str, -2) == 'by'
            OR substr($str, -2) == 'ny'
            OR substr($str, -2) == 'my' )
        {
            $str = substr($str, 1) . 'ies';
        }
        elseif ( substr($str, -1) == 'f' )
        {
            $str = substr($str, 1) . 'ves';
        }
        elseif ( substr($str, -2) == 'fe' )
        {
            $str = substr($str, 2) . 'ves';
        }
        elseif ( substr($str, -2) == 'is' )
        {
            $str = substr($str, 2) . 'es';
        }
        else
        {
            $str = $str . 's';
        }
        return $str;
}
#5

[eluser]xwero[/eluser]
the massive OR check can be written as
Code:
preg_match('/(b|c|d|f|g|h|j|k|l|m|n|p|r|s|t|v|w|x|z)y$/',substr($str, -2))
preg functions are slower but they pack a lot of goodness.
#6

[eluser]sophistry[/eluser]
@xwero - that preg functions are slower is a common myth; you just have to know what you are doing. in general a simple problem like a substring is faster in a single function call, but certain things can actually be way faster with preg functions.

Code:
<?php

class Tester extends Controller {

    function Tester()
    {
        parent::Controller();    

    }
    
    function test_preg($str='')
    {
    
        //
        $tot = 1000;
        
        // start with a comparable substring check
        $i = 1;
        $time_start = $this->microtime_float();
        while ($i <= $tot)
        {
        if ( substr($str, -2) == 'wy'
            OR substr($str, -2) == 'ry'
            OR substr($str, -2) == 'ty'
            OR substr($str, -2) == 'py'
            OR substr($str, -2) == 'sy'
            OR substr($str, -2) == 'dy'
            OR substr($str, -2) == 'fy'
            OR substr($str, -2) == 'gy'
            OR substr($str, -2) == 'hy'
            OR substr($str, -2) == 'jy'
            OR substr($str, -2) == 'ky'
            OR substr($str, -2) == 'ly'
            OR substr($str, -2) == 'zy'
            OR substr($str, -2) == 'xy'
            OR substr($str, -2) == 'cy'
            OR substr($str, -2) == 'vy'
            OR substr($str, -2) == 'by'
            OR substr($str, -2) == 'ny'
            OR substr($str, -2) == 'my' )
            { $c = 1; }
           $i++;
        }
        $time_end = $this->microtime_float();
        $time = $time_end - $time_start;
        
        $this->pre($time);
        
        
        // now test xwero's working, but unoptimized regex
        $i = 1;
        $time_start = $this->microtime_float();
        while ($i <= $tot)
        {
            $c = preg_match('/(b|c|d|f|g|h|j|k|l|m|n|p|r|s|t|v|w|x|z)y$/',substr($str, -2));
            $i++;
        }
        $time_end = $this->microtime_float();
        $time = $time_end - $time_start;
        
        $this->pre($time);
        
        // optimized regex - it's the fastest, BTW
        $i = 1;
        $time_start = $this->microtime_float();
        while ($i <= $tot)
        {
            $c = preg_match('/[bcdfghjklmnprstvwxz]y$/',$str);            
            $i++;
        }
        $time_end = $this->microtime_float();
        $time = $time_end - $time_start;
        
        $this->pre($time);
        
        
        
    }
    
    function microtime_float()
    {
       list($usec, $sec) = explode(' ', microtime());
       return ((float)$usec + (float)$sec);
    }
    
    // function to print with pre
    function pre($x){echo '<pre>';print_r($x);echo '</pre>';}
}
#7

[eluser]xwero[/eluser]
Oh yes that is a better regex. Stupid of me using pipes when i could us a character group and cutting the string. Nice catch sophistry.

I guess i was looking too much at the first check where you have to do
Code:
preg_match('/(?:sh|ch|x|z|s)$/',str)
#8

[eluser]sophistry[/eluser]
as long as we're talking optimization... there are a few things you can do with this function to make it better without going to regex.

just make two variables called $str_minus_1 and $str_minus_2 and then test against those instead of calling substr() 31 separate times.




Theme © iAndrew 2016 - Forum software by © MyBB