InflectionSingularizeTrait::doSingularize()   B
last analyzed

Complexity

Conditions 7
Paths 15

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 11
nc 15
nop 1
dl 0
loc 22
ccs 0
cts 12
cp 0
crap 56
rs 8.8333
c 1
b 0
f 0
1
<?php
2
3
namespace Nip\Inflector\Traits;
4
5
/**
6
 * Trait InflectionSingularizeTrait
7
 * @package Nip\Inflector\Traits
8
 *
9
 * @method singularize($string)
10
 */
11
trait InflectionSingularizeTrait
12
{
13
    protected $singular = [
14
        'rules' => [
15
            '/(s)tatuses$/i' => '\1\2tatus',
16
            '/^(.*)(menu)s$/i' => '\1\2',
17
            '/(quiz)zes$/i' => '\\1',
18
            '/(matr)ices$/i' => '\1ix',
19
            '/(vert|ind)ices$/i' => '\1ex',
20
            '/^(ox)en/i' => '\1',
21
            '/(alias)(es)*$/i' => '\1',
22
            '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
23
            '/([ftw]ax)es/i' => '\1',
24
            '/(cris|ax|test)es$/i' => '\1is',
25
            '/(shoe)s$/i' => '\1',
26
            '/(o)es$/i' => '\1',
27
            '/ouses$/' => 'ouse',
28
            '/([^a])uses$/' => '\1us',
29
            '/([m|l])ice$/i' => '\1ouse',
30
            '/(x|ch|ss|sh)es$/i' => '\1',
31
            '/(m)ovies$/i' => '\1\2ovie',
32
            '/(s)eries$/i' => '\1\2eries',
33
            '/([^aeiouy]|qu)ies$/i' => '\1y',
34
            '/(tive)s$/i' => '\1',
35
            '/(hive)s$/i' => '\1',
36
            '/(drive)s$/i' => '\1',
37
            '/([le])ves$/i' => '\1f',
38
            '/([^rfoa])ves$/i' => '\1fe',
39
            '/(^analy)ses$/i' => '\1sis',
40
            '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
41
            '/([ti])a$/i' => '\1um',
42
            '/(p)eople$/i' => '\1\2erson',
43
            '/(m)en$/i' => '\1an',
44
            '/(c)hildren$/i' => '\1\2hild',
45
            '/(n)ews$/i' => '\1\2ews',
46
            '/eaus$/' => 'eau',
47
            '/^(.*us)$/' => '\\1',
48
            '/s$/i' => ''
49
        ],
50
        'uncountable' => [
51
            '.*[nrlm]ese',
52
            '.*data',
53
            '.*deer',
54
            '.*fish',
55
            '.*measles',
56
            '.*ois',
57
            '.*pox',
58
            '.*sheep',
59
            'people',
60
            'feedback',
61
            'stadia',
62
            '.*?media',
63
            'chassis',
64
            'clippers',
65
            'debris',
66
            'diabetes',
67
            'equipment',
68
            'gallows',
69
            'graffiti',
70
            'headquarters',
71
            'information',
72
            'innings',
73
            'news',
74
            'nexus',
75
            'pokemon',
76
            'proceedings',
77
            'research',
78
            'sea[- ]bass',
79
            'series',
80
            'species',
81
            'weather'
82
        ],
83
        'irregular' => [
84
            'atlas' => 'atlases',
85
            'beef' => 'beefs',
86
            'brief' => 'briefs',
87
            'brother' => 'brothers',
88
            'cafe' => 'cafes',
89
            'child' => 'children',
90
            'cookie' => 'cookies',
91
            'corpus' => 'corpuses',
92
            'cow' => 'cows',
93
            'criterion' => 'criteria',
94
            'ganglion' => 'ganglions',
95
            'genie' => 'genies',
96
            'genus' => 'genera',
97
            'graffito' => 'graffiti',
98
            'hoof' => 'hoofs',
99
            'loaf' => 'loaves',
100
            'man' => 'men',
101
            'money' => 'monies',
102
            'mongoose' => 'mongooses',
103
            'move' => 'moves',
104
            'mythos' => 'mythoi',
105
            'niche' => 'niches',
106
            'numen' => 'numina',
107
            'occiput' => 'occiputs',
108
            'octopus' => 'octopuses',
109
            'opus' => 'opuses',
110
            'ox' => 'oxen',
111
            'penis' => 'penises',
112
            'person' => 'people',
113
            'sex' => 'sexes',
114
            'soliloquy' => 'soliloquies',
115
            'testis' => 'testes',
116
            'trilby' => 'trilbys',
117
            'turf' => 'turfs',
118
            'potato' => 'potatoes',
119
            'hero' => 'heroes',
120
            'tooth' => 'teeth',
121
            'goose' => 'geese',
122
            'foot' => 'feet',
123
            'foe' => 'foes',
124
            'sieve' => 'sieves'
125
        ]
126
    ];
127
128
    /**
129
     * @param $word
130
     * @return mixed
131
     */
132
    protected function doSingularize($word)
133
    {
134
        $lowercased_word = strtolower($word);
135
        foreach ($this->singular['uncountable'] as $_uncountable) {
136
            if (substr($lowercased_word, (-1 * strlen($_uncountable))) == $_uncountable) {
137
                return $word;
138
            }
139
        }
140
141
        foreach ($this->singular['irregular'] as $_plural => $_singular) {
142
            if (preg_match('/(' . $_singular . ')$/i', $word, $arr)) {
143
                return preg_replace('/(' . $_singular . ')$/i', substr($arr[0], 0, 1) . substr($_plural, 1), $word);
144
            }
145
        }
146
147
        foreach ($this->singular['rules'] as $rule => $replacement) {
148
            if (preg_match($rule, $word)) {
149
                return preg_replace($rule, $replacement, $word);
150
            }
151
        }
152
153
        return $word;
154
    }
155
}
156