primo commit
This commit is contained in:
420
libraries/fof40/Inflector/Inflector.php
Normal file
420
libraries/fof40/Inflector/Inflector.php
Normal file
@ -0,0 +1,420 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace FOF40\Inflector;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
/**
|
||||
* An Inflector to pluralize and singularize English nouns.
|
||||
*/
|
||||
class Inflector
|
||||
{
|
||||
/**
|
||||
* Rules for pluralizing and singularizing of nouns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [
|
||||
// Pluralization rules. The regex on the left transforms to the regex on the right.
|
||||
'pluralization' => [
|
||||
'/move$/i' => 'moves',
|
||||
'/sex$/i' => 'sexes',
|
||||
'/child$/i' => 'children',
|
||||
'/children$/i' => 'children',
|
||||
'/man$/i' => 'men',
|
||||
'/men$/i' => 'men',
|
||||
'/foot$/i' => 'feet',
|
||||
'/feet$/i' => 'feet',
|
||||
'/person$/i' => 'people',
|
||||
'/people$/i' => 'people',
|
||||
'/taxon$/i' => 'taxa',
|
||||
'/taxa$/i' => 'taxa',
|
||||
'/(quiz)$/i' => '$1zes',
|
||||
'/^(ox)$/i' => '$1en',
|
||||
'/oxen$/i' => 'oxen',
|
||||
'/(m|l)ouse$/i' => '$1ice',
|
||||
'/(m|l)ice$/i' => '$1ice',
|
||||
'/(matr|vert|ind|suff)ix|ex$/i' => '$1ices',
|
||||
'/(x|ch|ss|sh)$/i' => '$1es',
|
||||
'/([^aeiouy]|qu)y$/i' => '$1ies',
|
||||
'/(?:([^f])fe|([lr])f)$/i' => '$1$2ves',
|
||||
'/sis$/i' => 'ses',
|
||||
'/([ti]|addend)um$/i' => '$1a',
|
||||
'/([ti]|addend)a$/i' => '$1a',
|
||||
'/(alumn|formul)a$/i' => '$1ae',
|
||||
'/(alumn|formul)ae$/i' => '$1ae',
|
||||
'/(buffal|tomat|her)o$/i' => '$1oes',
|
||||
'/(bu)s$/i' => '$1ses',
|
||||
'/(campu)s$/i' => '$1ses',
|
||||
'/(alias|status)$/i' => '$1es',
|
||||
'/(octop|vir)us$/i' => '$1i',
|
||||
'/(octop|vir)i$/i' => '$1i',
|
||||
'/(gen)us$/i' => '$1era',
|
||||
'/(gen)era$/i' => '$1era',
|
||||
'/(ax|test)is$/i' => '$1es',
|
||||
'/s$/i' => 's',
|
||||
'/$/' => 's',
|
||||
],
|
||||
// Singularization rules. The regex on the left transforms to the regex on the right.
|
||||
'singularization' => [
|
||||
'/cookies$/i' => 'cookie',
|
||||
'/moves$/i' => 'move',
|
||||
'/sexes$/i' => 'sex',
|
||||
'/children$/i' => 'child',
|
||||
'/men$/i' => 'man',
|
||||
'/feet$/i' => 'foot',
|
||||
'/people$/i' => 'person',
|
||||
'/taxa$/i' => 'taxon',
|
||||
'/databases$/i' => 'database',
|
||||
'/menus$/i' => 'menu',
|
||||
'/(quiz)zes$/i' => '\1',
|
||||
'/(matr|suff)ices$/i' => '\1ix',
|
||||
'/(vert|ind|cod)ices$/i' => '\1ex',
|
||||
'/^(ox)en/i' => '\1',
|
||||
'/(alias|status)es$/i' => '\1',
|
||||
'/(tomato|hero|buffalo)es$/i' => '\1',
|
||||
'/([octop|vir])i$/i' => '\1us',
|
||||
'/(gen)era$/i' => '\1us',
|
||||
'/(cris|^ax|test)es$/i' => '\1is',
|
||||
'/is$/i' => 'is',
|
||||
'/us$/i' => 'us',
|
||||
'/ias$/i' => 'ias',
|
||||
'/(shoe)s$/i' => '\1',
|
||||
'/(o)es$/i' => '\1e',
|
||||
'/(bus)es$/i' => '\1',
|
||||
'/(campus)es$/i' => '\1',
|
||||
'/([m|l])ice$/i' => '\1ouse',
|
||||
'/(x|ch|ss|sh)es$/i' => '\1',
|
||||
'/(m)ovies$/i' => '\1ovie',
|
||||
'/(s)eries$/i' => '\1eries',
|
||||
'/(v)ies$/i' => '\1ie',
|
||||
'/([^aeiouy]|qu)ies$/i' => '\1y',
|
||||
'/([lr])ves$/i' => '\1f',
|
||||
'/(tive)s$/i' => '\1',
|
||||
'/(hive)s$/i' => '\1',
|
||||
'/([^f])ves$/i' => '\1fe',
|
||||
'/(^analy)ses$/i' => '\1sis',
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
|
||||
'/([ti]|addend)a$/i' => '\1um',
|
||||
'/(alumn|formul)ae$/i' => '$1a',
|
||||
'/(n)ews$/i' => '\1ews',
|
||||
'/(.*)ss$/i' => '\1ss',
|
||||
'/(.*)s$/i' => '\1',
|
||||
],
|
||||
// Uncountable objects are always singular
|
||||
'uncountable' => [
|
||||
'aircraft',
|
||||
'cannon',
|
||||
'deer',
|
||||
'equipment',
|
||||
'fish',
|
||||
'information',
|
||||
'money',
|
||||
'moose',
|
||||
'news',
|
||||
'rice',
|
||||
'series',
|
||||
'sheep',
|
||||
'species',
|
||||
'swine',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Cache of pluralized and singularized nouns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cache = [
|
||||
'singularized' => [],
|
||||
'pluralized' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* Removes the cache of pluralised and singularised words. Useful when you want to replace word pairs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCache(): void
|
||||
{
|
||||
$this->cache['pluralized'] = [];
|
||||
$this->cache['singularized'] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a word to the cache, useful to make exceptions or to add words in other languages.
|
||||
*
|
||||
* @param string $singular word.
|
||||
* @param string $plural word.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addWord(string $singular, string $plural): void
|
||||
{
|
||||
$this->cache['pluralized'][$singular] = $plural;
|
||||
$this->cache['singularized'][$plural] = $singular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Singular English word to plural.
|
||||
*
|
||||
* @param string $word word to pluralize.
|
||||
*
|
||||
* @return string Plural noun.
|
||||
*/
|
||||
public function pluralize(string $word): string
|
||||
{
|
||||
// Get the cached noun of it exists
|
||||
if (isset($this->cache['pluralized'][$word]))
|
||||
{
|
||||
return $this->cache['pluralized'][$word];
|
||||
}
|
||||
|
||||
// Check if the noun is already in plural form, i.e. in the singularized cache
|
||||
if (isset($this->cache['singularized'][$word]))
|
||||
{
|
||||
return $word;
|
||||
}
|
||||
|
||||
// Create the plural noun
|
||||
if (in_array($word, $this->rules['uncountable']))
|
||||
{
|
||||
$_cache['pluralized'][$word] = $word;
|
||||
|
||||
return $word;
|
||||
}
|
||||
|
||||
foreach ($this->rules['pluralization'] as $regexp => $replacement)
|
||||
{
|
||||
$matches = null;
|
||||
$plural = preg_replace($regexp, $replacement, $word, -1, $matches);
|
||||
|
||||
if ($matches > 0)
|
||||
{
|
||||
$_cache['pluralized'][$word] = $plural;
|
||||
|
||||
return $plural;
|
||||
}
|
||||
}
|
||||
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plural English word to singular.
|
||||
*
|
||||
* @param string $word Word to singularize.
|
||||
*
|
||||
* @return string Singular noun.
|
||||
*/
|
||||
public function singularize(string $word): string
|
||||
{
|
||||
// Get the cached noun of it exists
|
||||
if (isset($this->cache['singularized'][$word]))
|
||||
{
|
||||
return $this->cache['singularized'][$word];
|
||||
}
|
||||
|
||||
// Check if the noun is already in singular form, i.e. in the pluralized cache
|
||||
if (isset($this->cache['pluralized'][$word]))
|
||||
{
|
||||
return $word;
|
||||
}
|
||||
|
||||
// Create the singular noun
|
||||
if (in_array($word, $this->rules['uncountable']))
|
||||
{
|
||||
$_cache['singularized'][$word] = $word;
|
||||
|
||||
return $word;
|
||||
}
|
||||
|
||||
foreach ($this->rules['singularization'] as $regexp => $replacement)
|
||||
{
|
||||
$matches = null;
|
||||
$singular = preg_replace($regexp, $replacement, $word, -1, $matches);
|
||||
|
||||
if ($matches > 0)
|
||||
{
|
||||
$_cache['singularized'][$word] = $singular;
|
||||
|
||||
return $singular;
|
||||
}
|
||||
}
|
||||
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given word as CamelCased.
|
||||
*
|
||||
* Converts a word like "foo_bar" or "foo bar" to "FooBar". It
|
||||
* will remove non alphanumeric characters from the word, so
|
||||
* "who's online" will be converted to "WhoSOnline"
|
||||
*
|
||||
* @param string $word Word to convert to camel case.
|
||||
*
|
||||
* @return string UpperCamelCasedWord
|
||||
*/
|
||||
public function camelize(string $word): string
|
||||
{
|
||||
$word = preg_replace('/[^a-zA-Z0-9\s]/', ' ', $word);
|
||||
|
||||
return str_replace(' ', '', ucwords(strtolower(str_replace('_', ' ', $word))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a word "into_it_s_underscored_version"
|
||||
*
|
||||
* Convert any "CamelCased" or "ordinary Word" into an "underscored_word".
|
||||
*
|
||||
* @param string $word Word to underscore
|
||||
*
|
||||
* @return string Underscored word
|
||||
*/
|
||||
public function underscore(string $word): string
|
||||
{
|
||||
$word = preg_replace('/(\s)+/', '_', $word);
|
||||
|
||||
return strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $word));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any "CamelCased" word into an array of strings
|
||||
*
|
||||
* Returns an array of strings each of which is a substring of string formed
|
||||
* by splitting it at the camelcased letters.
|
||||
*
|
||||
* @param string $word Word to explode
|
||||
*
|
||||
* @return string[] Array of strings
|
||||
*/
|
||||
public function explode(string $word): array
|
||||
{
|
||||
return explode('_', self::underscore($word));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of strings into a "CamelCased" word.
|
||||
*
|
||||
* @param string[] $words Array of words to implode
|
||||
*
|
||||
* @return string UpperCamelCasedWord
|
||||
*/
|
||||
public function implode(array $words): string
|
||||
{
|
||||
return self::camelize(implode('_', $words));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable string from $word.
|
||||
*
|
||||
* Returns a human-readable string from $word, by replacing
|
||||
* underscores with a space, and by upper-casing the initial
|
||||
* character by default.
|
||||
*
|
||||
* @param string $word String to "humanize"
|
||||
*
|
||||
* @return string Human-readable word
|
||||
*/
|
||||
public function humanize(string $word): string
|
||||
{
|
||||
return ucwords(strtolower(str_replace("_", " ", $word)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns camelBacked version of a string. Same as camelize but first char is lowercased.
|
||||
*
|
||||
* @param string $string String to be camelBacked.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @see self::camelize()
|
||||
*/
|
||||
public function variablize(string $string): string
|
||||
{
|
||||
$string = self::camelize(self::underscore($string));
|
||||
$result = strtolower(substr($string, 0, 1));
|
||||
|
||||
return preg_replace('/\\w/', $result, $string, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if an English word is singular
|
||||
*
|
||||
* @param string $string The word to check
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSingular(string $string): bool
|
||||
{
|
||||
// Check cache assuming the string is plural.
|
||||
$singular = $this->cache['singularized'][$string] ?? null;
|
||||
$plural = $singular && isset($this->cache['pluralized'][$singular]) ? $this->cache['pluralized'][$singular] : null;
|
||||
|
||||
if ($singular && $plural)
|
||||
{
|
||||
return $plural != $string;
|
||||
}
|
||||
|
||||
// If string is not in the cache, try to pluralize and singularize it.
|
||||
return self::singularize(self::pluralize($string)) === $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if an English word is plural.
|
||||
*
|
||||
* @param string $string String to be checked.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isPlural(string $string): bool
|
||||
{
|
||||
// Uncountable objects are always singular (e.g. information)
|
||||
if (in_array($string, $this->rules['uncountable']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check cache assuming the string is singular.
|
||||
$plural = $this->cache['pluralized'][$string] ?? null;
|
||||
$singular = $plural && isset($this->cache['singularized'][$plural]) ? $this->cache['singularized'][$plural] : null;
|
||||
|
||||
if ($plural && $singular)
|
||||
{
|
||||
return $singular != $string;
|
||||
}
|
||||
|
||||
// If string is not in the cache, try to singularize and pluralize it.
|
||||
return self::pluralize(self::singularize($string)) === $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a part of a CamelCased word by index.
|
||||
*
|
||||
* Use a negative index to start at the last part of the word (-1 is the
|
||||
* last part)
|
||||
*
|
||||
* @param string $string Word
|
||||
* @param integer $index Index of the part
|
||||
* @param string|null $default Default value
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPart(string $string, int $index, ?string $default = null): ?string
|
||||
{
|
||||
$parts = self::explode($string);
|
||||
|
||||
if ($index < 0)
|
||||
{
|
||||
$index = count($parts) + $index;
|
||||
}
|
||||
|
||||
return $parts[$index] ?? $default;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user