diff options
Diffstat (limited to 'vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php')
-rw-r--r-- | vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php new file mode 100644 index 00000000..e782cc10 --- /dev/null +++ b/vendor/symfony/property-access/Symfony/Component/PropertyAccess/StringUtil.php | |||
@@ -0,0 +1,195 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of the Symfony package. | ||
5 | * | ||
6 | * (c) Fabien Potencier <fabien@symfony.com> | ||
7 | * | ||
8 | * For the full copyright and license information, please view the LICENSE | ||
9 | * file that was distributed with this source code. | ||
10 | */ | ||
11 | |||
12 | namespace Symfony\Component\PropertyAccess; | ||
13 | |||
14 | /** | ||
15 | * Creates singulars from plurals. | ||
16 | * | ||
17 | * @author Bernhard Schussek <bschussek@gmail.com> | ||
18 | */ | ||
19 | class StringUtil | ||
20 | { | ||
21 | /** | ||
22 | * Map english plural to singular suffixes | ||
23 | * | ||
24 | * @var array | ||
25 | * | ||
26 | * @see http://english-zone.com/spelling/plurals.html | ||
27 | * @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English | ||
28 | */ | ||
29 | private static $pluralMap = array( | ||
30 | // First entry: plural suffix, reversed | ||
31 | // Second entry: length of plural suffix | ||
32 | // Third entry: Whether the suffix may succeed a vocal | ||
33 | // Fourth entry: Whether the suffix may succeed a consonant | ||
34 | // Fifth entry: singular suffix, normal | ||
35 | |||
36 | // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) | ||
37 | array('a', 1, true, true, array('on', 'um')), | ||
38 | |||
39 | // nebulae (nebula) | ||
40 | array('ea', 2, true, true, 'a'), | ||
41 | |||
42 | // mice (mouse), lice (louse) | ||
43 | array('eci', 3, false, true, 'ouse'), | ||
44 | |||
45 | // geese (goose) | ||
46 | array('esee', 4, false, true, 'oose'), | ||
47 | |||
48 | // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) | ||
49 | array('i', 1, true, true, 'us'), | ||
50 | |||
51 | // men (man), women (woman) | ||
52 | array('nem', 3, true, true, 'man'), | ||
53 | |||
54 | // children (child) | ||
55 | array('nerdlihc', 8, true, true, 'child'), | ||
56 | |||
57 | // oxen (ox) | ||
58 | array('nexo', 4, false, false, 'ox'), | ||
59 | |||
60 | // indices (index), appendices (appendix), prices (price) | ||
61 | array('seci', 4, false, true, array('ex', 'ix', 'ice')), | ||
62 | |||
63 | // babies (baby) | ||
64 | array('sei', 3, false, true, 'y'), | ||
65 | |||
66 | // analyses (analysis), ellipses (ellipsis), funguses (fungus), | ||
67 | // neuroses (neurosis), theses (thesis), emphases (emphasis), | ||
68 | // oases (oasis), crises (crisis), houses (house), bases (base), | ||
69 | // atlases (atlas), kisses (kiss) | ||
70 | array('ses', 3, true, true, array('s', 'se', 'sis')), | ||
71 | |||
72 | // objectives (objective), alternative (alternatives) | ||
73 | array('sevit', 5, true, true, 'tive'), | ||
74 | |||
75 | // lives (life), wives (wife) | ||
76 | array('sevi', 4, false, true, 'ife'), | ||
77 | |||
78 | // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) | ||
79 | array('sev', 3, true, true, 'f'), | ||
80 | |||
81 | // axes (axis), axes (ax), axes (axe) | ||
82 | array('sexa', 4, false, false, array('ax', 'axe', 'axis')), | ||
83 | |||
84 | // indexes (index), matrixes (matrix) | ||
85 | array('sex', 3, true, false, 'x'), | ||
86 | |||
87 | // quizzes (quiz) | ||
88 | array('sezz', 4, true, false, 'z'), | ||
89 | |||
90 | // bureaus (bureau) | ||
91 | array('suae', 4, false, true, 'eau'), | ||
92 | |||
93 | // roses (rose), garages (garage), cassettes (cassette), | ||
94 | // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), | ||
95 | // shoes (shoe) | ||
96 | array('se', 2, true, true, array('', 'e')), | ||
97 | |||
98 | // tags (tag) | ||
99 | array('s', 1, true, true, ''), | ||
100 | |||
101 | // chateaux (chateau) | ||
102 | array('xuae', 4, false, true, 'eau'), | ||
103 | ); | ||
104 | |||
105 | /** | ||
106 | * This class should not be instantiated | ||
107 | */ | ||
108 | private function __construct() {} | ||
109 | |||
110 | /** | ||
111 | * Returns the singular form of a word | ||
112 | * | ||
113 | * If the method can't determine the form with certainty, an array of the | ||
114 | * possible singulars is returned. | ||
115 | * | ||
116 | * @param string $plural A word in plural form | ||
117 | * @return string|array The singular form or an array of possible singular | ||
118 | * forms | ||
119 | */ | ||
120 | public static function singularify($plural) | ||
121 | { | ||
122 | $pluralRev = strrev($plural); | ||
123 | $lowerPluralRev = strtolower($pluralRev); | ||
124 | $pluralLength = strlen($lowerPluralRev); | ||
125 | |||
126 | // The outer loop iterates over the entries of the plural table | ||
127 | // The inner loop $j iterates over the characters of the plural suffix | ||
128 | // in the plural table to compare them with the characters of the actual | ||
129 | // given plural suffix | ||
130 | foreach (self::$pluralMap as $map) { | ||
131 | $suffix = $map[0]; | ||
132 | $suffixLength = $map[1]; | ||
133 | $j = 0; | ||
134 | |||
135 | // Compare characters in the plural table and of the suffix of the | ||
136 | // given plural one by one | ||
137 | while ($suffix[$j] === $lowerPluralRev[$j]) { | ||
138 | // Let $j point to the next character | ||
139 | ++$j; | ||
140 | |||
141 | // Successfully compared the last character | ||
142 | // Add an entry with the singular suffix to the singular array | ||
143 | if ($j === $suffixLength) { | ||
144 | // Is there any character preceding the suffix in the plural string? | ||
145 | if ($j < $pluralLength) { | ||
146 | $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]); | ||
147 | |||
148 | if (!$map[2] && $nextIsVocal) { | ||
149 | // suffix may not succeed a vocal but next char is one | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | if (!$map[3] && !$nextIsVocal) { | ||
154 | // suffix may not succeed a consonant but next char is one | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | $newBase = substr($plural, 0, $pluralLength - $suffixLength); | ||
160 | $newSuffix = $map[4]; | ||
161 | |||
162 | // Check whether the first character in the plural suffix | ||
163 | // is uppercased. If yes, uppercase the first character in | ||
164 | // the singular suffix too | ||
165 | $firstUpper = ctype_upper($pluralRev[$j - 1]); | ||
166 | |||
167 | if (is_array($newSuffix)) { | ||
168 | $singulars = array(); | ||
169 | |||
170 | foreach ($newSuffix as $newSuffixEntry) { | ||
171 | $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); | ||
172 | } | ||
173 | |||
174 | return $singulars; | ||
175 | } | ||
176 | |||
177 | return $newBase.($firstUpper ? ucFirst($newSuffix) : $newSuffix); | ||
178 | } | ||
179 | |||
180 | // Suffix is longer than word | ||
181 | if ($j === $pluralLength) { | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | // Convert teeth to tooth, feet to foot | ||
188 | if (false !== ($pos = strpos($plural, 'ee'))) { | ||
189 | return substr_replace($plural, 'oo', $pos, 2); | ||
190 | } | ||
191 | |||
192 | // Assume that plural and singular is identical | ||
193 | return $plural; | ||
194 | } | ||
195 | } | ||