composer package updates
[openemr.git] / vendor / doctrine / inflector / lib / Doctrine / Common / Inflector / Inflector.php
blob3a951af8d4a43d88f1b8aeed56c8221ef4ebe7fa
1 <?php
2 /*
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
20 namespace Doctrine\Common\Inflector;
22 /**
23 * Doctrine inflector has static methods for inflecting text.
25 * The methods in these classes are from several different sources collected
26 * across several different php projects and several different authors. The
27 * original author names and emails are not known.
29 * Pluralize & Singularize implementation are borrowed from CakePHP with some modifications.
31 * @link www.doctrine-project.org
32 * @since 1.0
33 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
34 * @author Jonathan H. Wage <jonwage@gmail.com>
36 class Inflector
38 /**
39 * Plural inflector rules.
41 * @var array
43 private static $plural = array(
44 'rules' => array(
45 '/(s)tatus$/i' => '\1\2tatuses',
46 '/(quiz)$/i' => '\1zes',
47 '/^(ox)$/i' => '\1\2en',
48 '/([m|l])ouse$/i' => '\1ice',
49 '/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
50 '/(x|ch|ss|sh)$/i' => '\1es',
51 '/([^aeiouy]|qu)y$/i' => '\1ies',
52 '/(hive|gulf)$/i' => '\1s',
53 '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
54 '/sis$/i' => 'ses',
55 '/([ti])um$/i' => '\1a',
56 '/(p)erson$/i' => '\1eople',
57 '/(m)an$/i' => '\1en',
58 '/(c)hild$/i' => '\1hildren',
59 '/(f)oot$/i' => '\1eet',
60 '/(buffal|her|potat|tomat|volcan)o$/i' => '\1\2oes',
61 '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
62 '/us$/i' => 'uses',
63 '/(alias)$/i' => '\1es',
64 '/(analys|ax|cris|test|thes)is$/i' => '\1es',
65 '/s$/' => 's',
66 '/^$/' => '',
67 '/$/' => 's',
69 'uninflected' => array(
70 '.*[nrlm]ese',
71 '.*deer',
72 '.*fish',
73 '.*measles',
74 '.*ois',
75 '.*pox',
76 '.*sheep',
77 'people',
78 'cookie',
79 'police',
81 'irregular' => array(
82 'atlas' => 'atlases',
83 'axe' => 'axes',
84 'beef' => 'beefs',
85 'brother' => 'brothers',
86 'cafe' => 'cafes',
87 'chateau' => 'chateaux',
88 'niveau' => 'niveaux',
89 'child' => 'children',
90 'cookie' => 'cookies',
91 'corpus' => 'corpuses',
92 'cow' => 'cows',
93 'criterion' => 'criteria',
94 'curriculum' => 'curricula',
95 'demo' => 'demos',
96 'domino' => 'dominoes',
97 'echo' => 'echoes',
98 'foot' => 'feet',
99 'fungus' => 'fungi',
100 'ganglion' => 'ganglions',
101 'genie' => 'genies',
102 'genus' => 'genera',
103 'graffito' => 'graffiti',
104 'hippopotamus' => 'hippopotami',
105 'hoof' => 'hoofs',
106 'human' => 'humans',
107 'iris' => 'irises',
108 'larva' => 'larvae',
109 'leaf' => 'leaves',
110 'loaf' => 'loaves',
111 'man' => 'men',
112 'medium' => 'media',
113 'memorandum' => 'memoranda',
114 'money' => 'monies',
115 'mongoose' => 'mongooses',
116 'motto' => 'mottoes',
117 'move' => 'moves',
118 'mythos' => 'mythoi',
119 'niche' => 'niches',
120 'nucleus' => 'nuclei',
121 'numen' => 'numina',
122 'occiput' => 'occiputs',
123 'octopus' => 'octopuses',
124 'opus' => 'opuses',
125 'ox' => 'oxen',
126 'passerby' => 'passersby',
127 'penis' => 'penises',
128 'person' => 'people',
129 'plateau' => 'plateaux',
130 'runner-up' => 'runners-up',
131 'sex' => 'sexes',
132 'soliloquy' => 'soliloquies',
133 'son-in-law' => 'sons-in-law',
134 'syllabus' => 'syllabi',
135 'testis' => 'testes',
136 'thief' => 'thieves',
137 'tooth' => 'teeth',
138 'tornado' => 'tornadoes',
139 'trilby' => 'trilbys',
140 'turf' => 'turfs',
141 'volcano' => 'volcanoes',
146 * Singular inflector rules.
148 * @var array
150 private static $singular = array(
151 'rules' => array(
152 '/(s)tatuses$/i' => '\1\2tatus',
153 '/^(.*)(menu)s$/i' => '\1\2',
154 '/(quiz)zes$/i' => '\\1',
155 '/(matr)ices$/i' => '\1ix',
156 '/(vert|ind)ices$/i' => '\1ex',
157 '/^(ox)en/i' => '\1',
158 '/(alias)(es)*$/i' => '\1',
159 '/(buffal|her|potat|tomat|volcan)oes$/i' => '\1o',
160 '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
161 '/([ftw]ax)es/i' => '\1',
162 '/(analys|ax|cris|test|thes)es$/i' => '\1is',
163 '/(shoe|slave)s$/i' => '\1',
164 '/(o)es$/i' => '\1',
165 '/ouses$/' => 'ouse',
166 '/([^a])uses$/' => '\1us',
167 '/([m|l])ice$/i' => '\1ouse',
168 '/(x|ch|ss|sh)es$/i' => '\1',
169 '/(m)ovies$/i' => '\1\2ovie',
170 '/(s)eries$/i' => '\1\2eries',
171 '/([^aeiouy]|qu)ies$/i' => '\1y',
172 '/([lr])ves$/i' => '\1f',
173 '/(tive)s$/i' => '\1',
174 '/(hive)s$/i' => '\1',
175 '/(drive)s$/i' => '\1',
176 '/(dive)s$/i' => '\1',
177 '/([^fo])ves$/i' => '\1fe',
178 '/(^analy)ses$/i' => '\1sis',
179 '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
180 '/([ti])a$/i' => '\1um',
181 '/(p)eople$/i' => '\1\2erson',
182 '/(m)en$/i' => '\1an',
183 '/(c)hildren$/i' => '\1\2hild',
184 '/(f)eet$/i' => '\1oot',
185 '/(n)ews$/i' => '\1\2ews',
186 '/eaus$/' => 'eau',
187 '/^(.*us)$/' => '\\1',
188 '/s$/i' => '',
190 'uninflected' => array(
191 '.*[nrlm]ese',
192 '.*deer',
193 '.*fish',
194 '.*measles',
195 '.*ois',
196 '.*pox',
197 '.*sheep',
198 '.*ss',
199 'police',
200 'pants',
201 'clothes',
203 'irregular' => array(
204 'caches' => 'cache',
205 'criteria' => 'criterion',
206 'curves' => 'curve',
207 'emphases' => 'emphasis',
208 'foes' => 'foe',
209 'hoaxes' => 'hoax',
210 'media' => 'medium',
211 'neuroses' => 'neurosis',
212 'waves' => 'wave',
213 'oases' => 'oasis',
218 * Words that should not be inflected.
220 * @var array
222 private static $uninflected = array(
223 'Amoyese', 'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus',
224 'carp', 'chassis', 'clippers', 'cod', 'coitus', 'Congoese', 'contretemps', 'corps',
225 'debris', 'diabetes', 'djinn', 'eland', 'elk', 'equipment', 'Faroese', 'flounder',
226 'Foochowese', 'Furniture', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
227 'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings',
228 'jackanapes', 'Kiplingese', 'Kongoese', 'Lucchese', 'Luggage', 'mackerel', 'Maltese', '.*?media',
229 'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese',
230 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese',
231 'proceedings', 'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors',
232 'sea[- ]bass', 'series', 'Shavese', 'shears', 'siemens', 'species', 'staff', 'swine',
233 'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese', 'whiting',
234 'wildebeest', 'Yengeese'
238 * Method cache array.
240 * @var array
242 private static $cache = array();
245 * The initial state of Inflector so reset() works.
247 * @var array
249 private static $initialState = array();
252 * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.
254 * @param string $word The word to tableize.
256 * @return string The tableized word.
258 public static function tableize($word)
260 return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word));
264 * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.
266 * @param string $word The word to classify.
268 * @return string The classified word.
270 public static function classify($word)
272 return str_replace(' ', '', ucwords(strtr($word, '_-', ' ')));
276 * Camelizes a word. This uses the classify() method and turns the first character to lowercase.
278 * @param string $word The word to camelize.
280 * @return string The camelized word.
282 public static function camelize($word)
284 return lcfirst(self::classify($word));
288 * Uppercases words with configurable delimeters between words.
290 * Takes a string and capitalizes all of the words, like PHP's built-in
291 * ucwords function. This extends that behavior, however, by allowing the
292 * word delimeters to be configured, rather than only separating on
293 * whitespace.
295 * Here is an example:
296 * <code>
297 * <?php
298 * $string = 'top-o-the-morning to all_of_you!';
299 * echo \Doctrine\Common\Inflector\Inflector::ucwords($string);
300 * // Top-O-The-Morning To All_of_you!
302 * echo \Doctrine\Common\Inflector\Inflector::ucwords($string, '-_ ');
303 * // Top-O-The-Morning To All_Of_You!
304 * ?>
305 * </code>
307 * @param string $string The string to operate on.
308 * @param string $delimiters A list of word separators.
310 * @return string The string with all delimeter-separated words capitalized.
312 public static function ucwords($string, $delimiters = " \n\t\r\0\x0B-")
314 return preg_replace_callback(
315 '/[^' . preg_quote($delimiters, '/') . ']+/',
316 function($matches) {
317 return ucfirst($matches[0]);
319 $string
324 * Clears Inflectors inflected value caches, and resets the inflection
325 * rules to the initial values.
327 * @return void
329 public static function reset()
331 if (empty(self::$initialState)) {
332 self::$initialState = get_class_vars('Inflector');
334 return;
337 foreach (self::$initialState as $key => $val) {
338 if ($key != 'initialState') {
339 self::${$key} = $val;
345 * Adds custom inflection $rules, of either 'plural' or 'singular' $type.
347 * ### Usage:
349 * {{{
350 * Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables'));
351 * Inflector::rules('plural', array(
352 * 'rules' => array('/^(inflect)ors$/i' => '\1ables'),
353 * 'uninflected' => array('dontinflectme'),
354 * 'irregular' => array('red' => 'redlings')
355 * ));
356 * }}}
358 * @param string $type The type of inflection, either 'plural' or 'singular'
359 * @param array $rules An array of rules to be added.
360 * @param boolean $reset If true, will unset default inflections for all
361 * new rules that are being defined in $rules.
363 * @return void
365 public static function rules($type, $rules, $reset = false)
367 foreach ($rules as $rule => $pattern) {
368 if ( ! is_array($pattern)) {
369 continue;
372 if ($reset) {
373 self::${$type}[$rule] = $pattern;
374 } else {
375 self::${$type}[$rule] = ($rule === 'uninflected')
376 ? array_merge($pattern, self::${$type}[$rule])
377 : $pattern + self::${$type}[$rule];
380 unset($rules[$rule], self::${$type}['cache' . ucfirst($rule)]);
382 if (isset(self::${$type}['merged'][$rule])) {
383 unset(self::${$type}['merged'][$rule]);
386 if ($type === 'plural') {
387 self::$cache['pluralize'] = self::$cache['tableize'] = array();
388 } elseif ($type === 'singular') {
389 self::$cache['singularize'] = array();
393 self::${$type}['rules'] = $rules + self::${$type}['rules'];
397 * Returns a word in plural form.
399 * @param string $word The word in singular form.
401 * @return string The word in plural form.
403 public static function pluralize($word)
405 if (isset(self::$cache['pluralize'][$word])) {
406 return self::$cache['pluralize'][$word];
409 if (!isset(self::$plural['merged']['irregular'])) {
410 self::$plural['merged']['irregular'] = self::$plural['irregular'];
413 if (!isset(self::$plural['merged']['uninflected'])) {
414 self::$plural['merged']['uninflected'] = array_merge(self::$plural['uninflected'], self::$uninflected);
417 if (!isset(self::$plural['cacheUninflected']) || !isset(self::$plural['cacheIrregular'])) {
418 self::$plural['cacheUninflected'] = '(?:' . implode('|', self::$plural['merged']['uninflected']) . ')';
419 self::$plural['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$plural['merged']['irregular'])) . ')';
422 if (preg_match('/(.*)\\b(' . self::$plural['cacheIrregular'] . ')$/i', $word, $regs)) {
423 self::$cache['pluralize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$plural['merged']['irregular'][strtolower($regs[2])], 1);
425 return self::$cache['pluralize'][$word];
428 if (preg_match('/^(' . self::$plural['cacheUninflected'] . ')$/i', $word, $regs)) {
429 self::$cache['pluralize'][$word] = $word;
431 return $word;
434 foreach (self::$plural['rules'] as $rule => $replacement) {
435 if (preg_match($rule, $word)) {
436 self::$cache['pluralize'][$word] = preg_replace($rule, $replacement, $word);
438 return self::$cache['pluralize'][$word];
444 * Returns a word in singular form.
446 * @param string $word The word in plural form.
448 * @return string The word in singular form.
450 public static function singularize($word)
452 if (isset(self::$cache['singularize'][$word])) {
453 return self::$cache['singularize'][$word];
456 if (!isset(self::$singular['merged']['uninflected'])) {
457 self::$singular['merged']['uninflected'] = array_merge(
458 self::$singular['uninflected'],
459 self::$uninflected
463 if (!isset(self::$singular['merged']['irregular'])) {
464 self::$singular['merged']['irregular'] = array_merge(
465 self::$singular['irregular'],
466 array_flip(self::$plural['irregular'])
470 if (!isset(self::$singular['cacheUninflected']) || !isset(self::$singular['cacheIrregular'])) {
471 self::$singular['cacheUninflected'] = '(?:' . join('|', self::$singular['merged']['uninflected']) . ')';
472 self::$singular['cacheIrregular'] = '(?:' . join('|', array_keys(self::$singular['merged']['irregular'])) . ')';
475 if (preg_match('/(.*)\\b(' . self::$singular['cacheIrregular'] . ')$/i', $word, $regs)) {
476 self::$cache['singularize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$singular['merged']['irregular'][strtolower($regs[2])], 1);
478 return self::$cache['singularize'][$word];
481 if (preg_match('/^(' . self::$singular['cacheUninflected'] . ')$/i', $word, $regs)) {
482 self::$cache['singularize'][$word] = $word;
484 return $word;
487 foreach (self::$singular['rules'] as $rule => $replacement) {
488 if (preg_match($rule, $word)) {
489 self::$cache['singularize'][$word] = preg_replace($rule, $replacement, $word);
491 return self::$cache['singularize'][$word];
495 self::$cache['singularize'][$word] = $word;
497 return $word;