Completed
Push — master ( 888771...c95d8a )
by Yuri
03:40 queued 12s
created

Formatter::capitalize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 13
ccs 6
cts 6
cp 1
rs 9.4285
cc 1
eloc 8
nc 1
nop 1
crap 1
1
<?php namespace Tamtamchik\NameCase;
2
3
/**
4
 * Class Formatter.
5
 */
6
class Formatter
7
{
8
    // Default options
9
    private static $options = [
10
        'lazy'    => true,
11
        'irish'   => true,
12
        'spanish' => true,
13
    ];
14
15
    // Irish exceptions
16
    private static $exceptionsIrish = [
17
        '\bMacEdo'     => 'Macedo',
18
        '\bMacEvicius' => 'Macevicius',
19
        '\bMacHado'    => 'Machado',
20
        '\bMacHar'     => 'Machar',
21
        '\bMacHin'     => 'Machin',
22
        '\bMacHlin'    => 'Machlin',
23
        '\bMacIas'     => 'Macias',
24
        '\bMacIulis'   => 'Maciulis',
25
        '\bMacKie'     => 'Mackie',
26
        '\bMacKle'     => 'Mackle',
27
        '\bMacKlin'    => 'Macklin',
28
        '\bMacKmin'    => 'Mackmin',
29
        '\bMacQuarie'  => 'Macquarie',
30
    ];
31
32
    // General replacements
33
    private static $replacements = [
34
        '\bAl(?=\s+\w)'         => 'al',        // al Arabic or forename Al.
35
        '\b(Bin|Binti|Binte)\b' => 'bin',       // bin, binti, binte Arabic
36
        '\bAp\b'                => 'ap',        // ap Welsh.
37
        '\bBen(?=\s+\w)'        => 'ben',       // ben Hebrew or forename Ben.
38
        '\bDell([ae])\b'        => 'dell\1',    // della and delle Italian.
39
        '\bD([aeiou])\b'        => 'd\1',       // da, de, di Italian; du French; do Brasil
40
        '\bD([ao]s)\b'          => 'd\1',       // das, dos Brasileiros
41
        '\bDe([lr])\b'          => 'de\1',      // del Italian; der Dutch/Flemish.
42
        '\bEl\b'                => 'el',        // el Greek or El Spanish.
43
        '\bLa\b'                => 'la',        // la French or La Spanish.
44
        '\bL([eo])\b'           => 'l\1',       // lo Italian; le French.
45
        '\bVan(?=\s+\w)'        => 'van',       // van German or forename Van.
46
        '\bVon\b'               => 'von',       // von Dutch/Flemish
47
    ];
48
49
    /**
50
     * Main function for NameCase.
51
     *
52
     * @param string $string
53
     * @param array  $options
54
     *
55
     * @return string
56
     */
57 6
    public static function nc($string, array $options = [])
58
    {
59 6
        $options = array_merge(self::$options, $options);
60
61
        // Do not do anything if string is mixed and lazy option is true.
62 6
        if ($options['lazy']) {
63 6
            if (self::skipMixed($string)) return $string;
64 6
        }
65
66 6
        $local = mb_strtolower($string);
67
68
        // Capitalize
69 6
        $local = self::capitalize($local);
70
71 6
        if ($options['irish']) {
72 6
            $local = self::updateIrish($local);
73 6
        }
74
75 6
        $local = self::updateIrish($local);
76
77
        // Fixes for "son (daughter) of" etc
78 6
        foreach (self::$replacements as $pattern => $replacement) {
79 6
            $local = mb_ereg_replace($pattern, $replacement, $local);
80 6
        }
81
82 6
        if ($options['spanish']) {
83 6
            foreach (["Y", "E", "I"] as $conjunction) {
84 6
                $local = mb_ereg_replace('\b' . $conjunction . '\b', mb_strtolower($conjunction), $local);
85 6
            }
86 6
        }
87
88 6
        return $local;
89
    }
90
91
    /**
92
     * Capitalize first letters.
93
     *
94
     * @param string $string
95
     *
96
     * @return string
97
     */
98 6
    private static function capitalize($string)
99
    {
100
        $string = \mb_ereg_replace_callback('\b\w', function ($matches) {
101 6
            return mb_strtoupper($matches[0]);
102 6
        }, $string);
103
104
        // Lowercase 's
105
        $string = \mb_ereg_replace_callback('\'\w\b', function ($matches) {
106 3
            return mb_strtolower($matches[0]);
107 6
        }, $string);
108
109 6
        return $string;
110
    }
111
112
    /**
113
     * Skip if string is mixed case.
114
     *
115
     * @param string $string
116
     *
117
     * @return bool
118
     */
119 6
    private static function skipMixed($string)
120
    {
121 6
        $firstLetterLower = $string[0] == mb_strtolower($string[0]);
122 6
        $allLowerOrUpper  = (mb_strtolower($string) == $string || mb_strtoupper($string) == $string);
123
124 6
        return ! ($firstLetterLower || $allLowerOrUpper);
125
    }
126
127
    /**
128
     * Fix Irish names.
129
     *
130
     * @param string $string
131
     *
132
     * @return string
133
     */
134 6
    private static function updateIrish($string)
135
    {
136 6
        if (mb_ereg_match('.*?\bMac[A-Za-z]{2,}[^aciozj]\b', $string) || mb_ereg_match('.*?\bMc', $string)) {
137
138 3
            $string = \mb_ereg_replace_callback('\b(Ma?c)([A-Za-z]+)', function ($matches) {
139 3
                return $matches[1] . mb_strtoupper(mb_substr($matches[2], 0, 1)) . mb_substr($matches[2], 1);
140 3
            }, $string);
141
142
            // Now fix "Mac" exceptions
143 3
            foreach (self::$exceptionsIrish as $pattern => $replacement) {
144 3
                $string = mb_ereg_replace($pattern, $replacement, $string);
145 3
            }
146 3
        }
147
148 6
        return mb_ereg_replace('Macmurdo', 'MacMurdo', $string);
149
    }
150
}
151