1: <?php namespace Illuminate\Support;
2:
3: class Pluralizer {
4:
5: 6: 7: 8: 9:
10: protected static $plural = array(
11: '/(quiz)$/i' => "$1zes",
12: '/^(ox)$/i' => "$1en",
13: '/([m|l])ouse$/i' => "$1ice",
14: '/(matr|vert|ind)ix|ex$/i' => "$1ices",
15: '/(x|ch|ss|sh)$/i' => "$1es",
16: '/([^aeiouy]|qu)y$/i' => "$1ies",
17: '/(hive)$/i' => "$1s",
18: '/(?:([^f])fe|([lr])f)$/i' => "$1$2ves",
19: '/(shea|lea|loa|thie)f$/i' => "$1ves",
20: '/sis$/i' => "ses",
21: '/([ti])um$/i' => "$1a",
22: '/(tomat|potat|ech|her|vet)o$/i' => "$1oes",
23: '/(bu)s$/i' => "$1ses",
24: '/(alias)$/i' => "$1es",
25: '/(octop)us$/i' => "$1i",
26: '/(ax|test)is$/i' => "$1es",
27: '/(us)$/i' => "$1es",
28: '/s$/i' => "s",
29: '/$/' => "s",
30: );
31:
32: 33: 34: 35: 36:
37: protected static $singular = array(
38: '/(quiz)zes$/i' => "$1",
39: '/(matr)ices$/i' => "$1ix",
40: '/(vert|ind)ices$/i' => "$1ex",
41: '/^(ox)en$/i' => "$1",
42: '/(alias)es$/i' => "$1",
43: '/(octop|vir)i$/i' => "$1us",
44: '/(cris|ax|test)es$/i' => "$1is",
45: '/(shoe)s$/i' => "$1",
46: '/(o)es$/i' => "$1",
47: '/(bus)es$/i' => "$1",
48: '/([m|l])ice$/i' => "$1ouse",
49: '/(x|ch|ss|sh)es$/i' => "$1",
50: '/(m)ovies$/i' => "$1ovie",
51: '/(s)eries$/i' => "$1eries",
52: '/([^aeiouy]|qu)ies$/i' => "$1y",
53: '/([lr])ves$/i' => "$1f",
54: '/(tive)s$/i' => "$1",
55: '/(hive)s$/i' => "$1",
56: '/(li|wi|kni)ves$/i' => "$1fe",
57: '/(shea|loa|lea|thie)ves$/i' => "$1f",
58: '/(^analy)ses$/i' => "$1sis",
59: '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis",
60: '/([ti])a$/i' => "$1um",
61: '/(n)ews$/i' => "$1ews",
62: '/(h|bl)ouses$/i' => "$1ouse",
63: '/(corpse)s$/i' => "$1",
64: '/(us)es$/i' => "$1",
65: '/(us|ss)$/i' => "$1",
66: '/s$/i' => "",
67: );
68:
69: 70: 71: 72: 73:
74: protected static $irregular = array(
75: 'child' => 'children',
76: 'foot' => 'feet',
77: 'goose' => 'geese',
78: 'man' => 'men',
79: 'move' => 'moves',
80: 'person' => 'people',
81: 'sex' => 'sexes',
82: 'tooth' => 'teeth',
83: );
84:
85: 86: 87: 88: 89:
90: protected static $uncountable = array(
91: 'audio',
92: 'equipment',
93: 'deer',
94: 'fish',
95: 'gold',
96: 'information',
97: 'money',
98: 'rice',
99: 'police',
100: 'series',
101: 'sheep',
102: 'species',
103: 'moose',
104: 'chassis',
105: 'traffic',
106: );
107:
108: 109: 110: 111: 112:
113: protected static $pluralCache = array();
114:
115: 116: 117: 118: 119:
120: protected static $singularCache = array();
121:
122: 123: 124: 125: 126: 127:
128: public static function singular($value)
129: {
130: if (isset(static::$singularCache[$value]))
131: {
132: return static::$singularCache[$value];
133: }
134:
135: $result = static::inflect($value, static::$singular, static::$irregular);
136:
137: return static::$singularCache[$value] = $result ?: $value;
138: }
139:
140: 141: 142: 143: 144: 145: 146:
147: public static function plural($value, $count = 2)
148: {
149: if ($count == 1) return $value;
150:
151:
152:
153:
154: if (isset(static::$pluralCache[$value]))
155: {
156: return static::$pluralCache[$value];
157: }
158:
159: $irregular = array_flip(static::$irregular);
160:
161:
162:
163:
164: $plural = static::$plural;
165:
166: $result = static::inflect($value, $plural, $irregular);
167:
168: return static::$pluralCache[$value] = $result;
169: }
170:
171: 172: 173: 174: 175: 176: 177: 178:
179: protected static function inflect($value, $source, $irregular)
180: {
181: if (static::uncountable($value)) return $value;
182:
183:
184:
185:
186: foreach ($irregular as $irregular => $pattern)
187: {
188: if (preg_match($pattern = '/'.$pattern.'$/i', $value))
189: {
190: $irregular = static::matchCase($irregular, $value);
191:
192: return preg_replace($pattern, $irregular, $value);
193: }
194: }
195:
196:
197:
198:
199: foreach ($source as $pattern => $inflected)
200: {
201: if (preg_match($pattern, $value))
202: {
203: $inflected = preg_replace($pattern, $inflected, $value);
204:
205: return static::matchCase($inflected, $value);
206: }
207: }
208: }
209:
210: 211: 212: 213: 214: 215:
216: protected static function uncountable($value)
217: {
218: return in_array(strtolower($value), static::$uncountable);
219: }
220:
221: 222: 223: 224: 225: 226: 227:
228: protected static function matchCase($value, $comparison)
229: {
230: $functions = array('mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords');
231:
232: foreach ($functions as $function)
233: {
234: if (call_user_func($function, $comparison) === $comparison)
235: {
236: return call_user_func($function, $value);
237: }
238: }
239:
240: return $value;
241: }
242:
243: }
244: