public static function singularize(string $plural)
    {
        $pluralRev = strrev($plural);
        $lowerPluralRev = strtolower($pluralRev);
        $pluralLength = \strlen($lowerPluralRev);

        // Check if the word is one which is not inflected, return early if so
        if (\in_array($lowerPluralRev, self::$uninflected, true)) {
            return $plural;
        }

        // The outer loop iterates over the entries of the plural table
        // The inner loop $j iterates over the characters of the plural suffix
        // in the plural table to compare them with the characters of the actual
        // given plural suffix
        foreach (self::$pluralMap as $map) {
            $suffix = $map[0];
            $suffixLength = $map[1];
            $j = 0;

            // Compare characters in the plural table and of the suffix of the
            // given plural one by one
            while ($suffix[$j] === $lowerPluralRev[$j]) {
                // Let $j point to the next character
                ++$j;

                // Successfully compared the last character
                // Add an entry with the singular suffix to the singular array
                if ($j === $suffixLength) {
                    // Is there any character preceding the suffix in the plural string?
                    if ($j < $pluralLength) {
                        $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);

                        if (!$map[2] && $nextIsVocal) {
                            // suffix may not succeed a vocal but next char is one
                            break;
                        }

                        if (!$map[3] && !$nextIsVocal) {
                            // suffix may not succeed a consonant but next char is one
                            break;
                        }
                    }

                    $newBase = substr($plural, 0, $pluralLength - $suffixLength);
                    $newSuffix = $map[4];

                    // Check whether the first character in the plural suffix
                    // is uppercased. If yes, uppercase the first character in
                    // the singular suffix too
                    $firstUpper = ctype_upper($pluralRev[$j - 1]);

                    if (\is_array($newSuffix)) {
                        $singulars = [];

                        foreach ($newSuffix as $newSuffixEntry) {
                            $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
                        }

                        return $singulars;
                    }

                    return $newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix);
                }

                // Suffix is longer than word
                if ($j === $pluralLength) {
                    break;
                }
            }
        }

        // Assume that plural and singular is identical
        return $plural;
    }
public static function singularize(string $plural)
    {
        $pluralRev = strrev($plural);
        $lowerPluralRev = strtolower($pluralRev);
        $pluralLength = \strlen($lowerPluralRev);

        // Check if the word is one which is not inflected, return early if so
        if (\in_array($lowerPluralRev, self::$uninflected, true)) {
            return $plural;
        }

        // The outer loop iterates over the entries of the plural table
        // The inner loop $j iterates over the characters of the plural suffix
        // in the plural table to compare them with the characters of the actual
        // given plural suffix
        foreach (self::$pluralMap as $map) {
            $suffix = $map[0];
            $suffixLength = $map[1];
            $j = 0;

            // Compare characters in the plural table and of the suffix of the
            // given plural one by one
            while ($suffix[$j] === $lowerPluralRev[$j]) {
                // Let $j point to the next character
                ++$j;

                // Successfully compared the last character
                // Add an entry with the singular suffix to the singular array
                if ($j === $suffixLength) {
                    // Is there any character preceding the suffix in the plural string?
                    if ($j < $pluralLength) {
                        $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);

                        if (!$map[2] && $nextIsVocal) {
                            // suffix may not succeed a vocal but next char is one
                            break;
                        }

                        if (!$map[3] && !$nextIsVocal) {
                            // suffix may not succeed a consonant but next char is one
                            break;
                        }
                    }

                    $newBase = substr($plural, 0, $pluralLength - $suffixLength);
                    $newSuffix = $map[4];

                    // Check whether the first character in the plural suffix
                    // is uppercased. If yes, uppercase the first character in
                    // the singular suffix too
                    $firstUpper = ctype_upper($pluralRev[$j - 1]);

                    if (\is_array($newSuffix)) {
                        $singulars = [];

                        foreach ($newSuffix as $newSuffixEntry) {
                            $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
                        }

                        return $singulars;
                    }

                    return $newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix);
                }

                // Suffix is longer than word
                if ($j === $pluralLength) {
                    break;
                }
            }
        }

        // Assume that plural and singular is identical
        return $plural;
    }
public static function singularize ( string $ plural ) { $ pluralRev = strrev ( $ plural ) ; $ lowerPluralRev = strtolower ( $ pluralRev ) ; $ pluralLength = \ strlen ( $ lowerPluralRev ) ; // Check if the word is one which is not inflected, return early if so if ( \ in_array ( $ lowerPluralRev , self :: $ uninflected , true ) ) { return $ plural ; } // The outer loop iterates over the entries of the plural table // The inner loop $j iterates over the characters of the plural suffix // in the plural table to compare them with the characters of the actual // given plural suffix foreach ( self :: $ pluralMap as $ map ) { $ suffix = $ map [ 0 ] ; $ suffixLength = $ map [ 1 ] ; $ j = 0 ; // Compare characters in the plural table and of the suffix of the // given plural one by one while ( $ suffix [ $ j ] === $ lowerPluralRev [ $ j ] ) { // Let $j point to the next character ++ $ j ; // Successfully compared the last character // Add an entry with the singular suffix to the singular array if ( $ j === $ suffixLength ) { // Is there any character preceding the suffix in the plural string? if ( $ j < $ pluralLength ) { $ nextIsVocal = false !== strpos ( 'aeiou' , $ lowerPluralRev [ $ j ] ) ; if ( ! $ map [ 2 ] && $ nextIsVocal ) { // suffix may not succeed a vocal but next char is one break ; } if ( ! $ map [ 3 ] && ! $ nextIsVocal ) { // suffix may not succeed a consonant but next char is one break ; } } $ newBase = substr ( $ plural , 0 , $ pluralLength - $ suffixLength ) ; $ newSuffix = $ map [ 4 ] ; // Check whether the first character in the plural suffix // is uppercased. If yes, uppercase the first character in // the singular suffix too $ firstUpper = ctype_upper ( $ pluralRev [ $ j - 1 ] ) ; if ( \ is_array ( $ newSuffix ) ) { $ singulars = [ ] ; foreach ( $ newSuffix as $ newSuffixEntry ) { $ singulars [ ] = $ newBase . ( $ firstUpper ? ucfirst ( $ newSuffixEntry ) : $ newSuffixEntry ) ; } return $ singulars ; } return $ newBase . ( $ firstUpper ? ucfirst ( $ newSuffix ) : $ newSuffix ) ; } // Suffix is longer than word if ( $ j === $ pluralLength ) { break ; } } } // Assume that plural and singular is identical return $ plural ; }
Returns the singular form of a word.

If the method can't determine the form with certainty, an array of the
possible singulars is returned.

@param string $plural A word in plural form

@return string|array The singular form or an array of possible singular forms
Returns the singular form of a word .