Code

< 40 %
40-60 %
> 60 %
1
<?php
2
namespace morphos;
3
4
use RuntimeException;
5
6
/**
7
 * Multibyte string helper
8
 */
9
class S
10
{
11
    /** @var string Encoding used for string manipulations */
12
    static protected $encoding;
13
14
    /** @var string[][] */
15
    static protected $cyrillicAlphabet = [
16
        ['Ё', 'Й', 'Ц', 'У', 'К', 'Е', 'Н', 'Г', 'Ш', 'Щ', 'З', 'Х', 'Ъ', 'Ф', 'Ы', 'В', 'А', 'П', 'Р', 'О', 'Л', 'Д', 'Ж', 'Э', 'Я', 'Ч', 'С', 'М', 'И', 'Т', 'Ь', 'Б', 'Ю'],
17
        ['ё', 'й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю'],
18
    ];
19
20
    /**
21
     * Sets encoding for all operations
22
     * @param string $encoding
23
     * @return void
24
     */
25
    public static function setEncoding($encoding)
26
    {
27
        static::$encoding = $encoding;
28
    }
29
30
    /**
31
     * Returns encoding used for all operations
32
     * @return string
33
     */
34 1767
    public static function getEncoding()
35
    {
36 1767
        return static::$encoding ?: 'utf-8';
37
    }
38
39
    /**
40
     * Calculates count of characters in string.
41
     * @param string $string
42
     * @return int|false
43
     */
44 47
    public static function length($string)
45
    {
46 47
        if (function_exists('mb_strlen')) {
47 47
            return mb_strlen($string, static::getEncoding());
48
        }
49
50
        if (function_exists('iconv_strlen')) {
51
            return iconv_strlen($string, static::getEncoding());
52
        }
53
54
        return false;
55
    }
56
57
    /**
58
     * Slices string like python.
59
     * @param string $string
60
     * @param int $start
61
     * @param int|null $end
62
     * @return string
63
     */
64 1503
    public static function slice($string, $start, $end = null)
65
    {
66 1503
        if ($end !== null) {
67 660
            $end -= $start;
68
        }
69
70 1503
        if (function_exists('mb_substr')) {
71 1503
            return mb_substr($string, $start, $end, static::getEncoding());
72
        }
73
74
        if (function_exists('iconv_substr')) {
75
            return iconv_substr($string, $start, $end ?: iconv_strlen($string), static::getEncoding());
76
        }
77
78
        throw new RuntimeException('Unreachable');
79
    }
80
81
    /**
82
     * Lower case.
83
     * @param string $string
84
     * @return string
85
     */
86 1758 View Code Duplication
    public static function lower($string)
87
    {
88 1758
        if (function_exists('mb_strtolower')) {
89 1758
            return mb_strtolower($string, static::getEncoding());
90
        }
91
92
        return static::replaceByMap($string, static::$cyrillicAlphabet[0], static::$cyrillicAlphabet[1]);
93
    }
94
95
    /**
96
     * Upper case.
97
     * @param string $string
98
     * @return bool|string
99
     */
100 220 View Code Duplication
    public static function upper($string)
101
    {
102 220
        if (function_exists('mb_strtoupper')) {
103 220
            return mb_strtoupper($string, static::getEncoding());
104
        }
105
106
        return static::replaceByMap($string, static::$cyrillicAlphabet[1], static::$cyrillicAlphabet[0]);
107
    }
108
109
    /**
110
     * Name case. (ex: Thomas, Lewis). Works properly with separated by '-' words
111
     * @param string $string
112
     * @return bool|string
113
     */
114 218
    public static function name($string)
115
    {
116 218
        if (strpos($string, '-') !== false) {
117
            return implode('-', array_map([__CLASS__, __FUNCTION__], explode('-', $string)));
118
        }
119
120 218
        return static::upper(static::slice($string, 0, 1)).static::lower(static::slice($string, 1));
121
    }
122
123
    /**
124
     * multiple substr_count().
125
     * @param string $string
126
     * @param string[] $chars
127
     * @return int
128
     */
129
    public static function countChars($string, array $chars)
130
    {
131
        if (function_exists('mb_split')) {
132
            return count(mb_split('('.implode('|', $chars).')', $string)) - 1;
133
        }
134
135
        $counter = 0;
136
        foreach ($chars as $char) {
137
            $counter += substr_count($string, $char);
138
        }
139
        return $counter;
140
    }
141
142
    /**
143
     * @param string $string
144
     * @param string $char
145
     * @return int|false
146
     */
147 12
    public static function findFirstPosition($string, $char)
148
    {
149 12
        if (function_exists('mb_strpos')) {
150 12
            return mb_strpos($string, $char, 0, static::getEncoding());
151
        }
152
153
        return strpos($string, $char);
154
    }
155
156
    /**
157
     * @param string $string
158
     * @param string $char
159
     * @return int|false
160
     */
161 6
    public static function findLastPosition($string, $char)
162
    {
163 6
        if (function_exists('mb_strrpos')) {
164 6
            return mb_strrpos($string, $char, 0, static::getEncoding());
165
        }
166
167
        return strrpos($string, $char);
168
    }
169
170
    /**
171
     * @param string $string
172
     * @param string[] $chars
173
     * @return string|false
174
     */
175 79
    public static function findLastPositionForOneOfChars($string, array $chars)
176
    {
177 79
        if (function_exists('mb_strrpos')) {
178 79
            $last_position = false;
179 79
            foreach ($chars as $char) {
180 79
                if (($pos = mb_strrpos($string, $char, 0, static::getEncoding())) !== false) {
181 79
                    if ($pos > $last_position) {
182 79
                        $last_position = $pos;
183
                    }
184
                }
185
            }
186 79
            if ($last_position !== false) {
187 79
                return mb_substr($string, $last_position, null, static::getEncoding());
188
            }
189 13
            return false;
190
        }
191
192
        return false;
193
    }
194
195
    /**
196
     * @param string $string
197
     * @param string $substring
198
     * @param bool $caseSensitive
199
     * @param int $startOffset
200
     * @return int|false
201
     */
202 120
    public static function indexOf($string, $substring, $caseSensitive = false, $startOffset = 0)
203
    {
204 120
        if (function_exists('mb_stripos')) {
205 120
            return $caseSensitive
206
                ? mb_strpos($string, $substring, $startOffset, static::getEncoding())
207 120
                : mb_stripos($string, $substring, $startOffset, static::getEncoding());
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * @param string $string
215
     * @param string[] $fromMap
216
     * @param string[] $toMap
217
     * @return string
218
     */
219
    private static function replaceByMap($string, $fromMap, $toMap)
220
    {
221
        $encoding = static::getEncoding();
222
        if ($encoding !== 'utf-8')
223
            $string = iconv($encoding, 'utf-8', $string);
224
225
        $string = strtr($string, array_combine($fromMap, $toMap));
226
227
        if ($encoding !== 'utf-8')
228
            $string = iconv('utf-8', $encoding, $string);
229
230
        return $string;
231
    }
232
233
    /**
234
     * Check that string has one of passed substrings
235
     * @param string $string
236
     * @param string[] $variants
237
     * @return bool
238
     */
239 3
    public static function stringContains($string, array $variants)
240
    {
241 3
        foreach ($variants as $variant) {
242 3
            if (static::findFirstPosition($string, $variant) !== false) {
243 3
                return true;
244
            }
245
        }
246 3
        return false;
247
    }
248
}
249