1<?php
2/**
3 * Created by PhpStorm.
4 * User: yf
5 * Date: 2018/5/22
6 * Time: 下午2:55
7 */
8
9namespace EasySwoole\Spl;
10
11
12class SplString extends SplStream
13{
14
15    function __construct( string $str = null )
16    {
17        parent::__construct( $str );
18    }
19
20    function setString( string $string ) : SplString
21    {
22        parent::truncate();
23        parent::rewind();
24        parent::write( $string );
25        return $this;
26    }
27
28    function split( int $length = 1 ) : SplArray
29    {
30        return new SplArray( str_split( $this->__toString(), $length ) );
31    }
32
33    function explode( string $delimiter ) : SplArray
34    {
35        return new SplArray( explode( $delimiter, $this->__toString() ) );
36    }
37
38    function subString( int $start, int $length ) : SplString
39    {
40        return $this->setString( substr( $this->__toString(), $start, $length ) );
41    }
42
43    function encodingConvert( string $desEncoding, $detectList
44    = [
45        'UTF-8',
46        'ASCII',
47        'GBK',
48        'GB2312',
49        'LATIN1',
50        'BIG5',
51        "UCS-2",
52    ] ) : SplString
53    {
54        $fileType = mb_detect_encoding( $this->__toString(), $detectList );
55        if( $fileType != $desEncoding ){
56            $this->setString( mb_convert_encoding( $this->__toString(), $desEncoding, $fileType ) );
57        }
58        return $this;
59    }
60
61    function utf8() : SplString
62    {
63        return $this->encodingConvert( "UTF-8" );
64    }
65
66    /*
67     * special function for unicode
68     */
69    function unicodeToUtf8() : SplString
70    {
71
72        $string = preg_replace_callback( '/\\\\u([0-9a-f]{4})/i', function( $matches ){
73            return mb_convert_encoding( pack( "H*", $matches[1] ), "UTF-8", "UCS-2BE" );
74        }, $this->__toString() );
75        return $this->setString( $string );
76    }
77
78    function toUnicode() : SplString
79    {
80        $raw = (string)$this->encodingConvert( "UCS-2" );
81        $len = strlen( $raw );
82        $str = '';
83        for( $i = 0 ; $i < $len - 1 ; $i = $i + 2 ){
84            $c  = $raw[$i];
85            $c2 = $raw[$i + 1];
86            if( ord( $c ) > 0 ){   //两个字节的文字
87                $str .= '\u'.base_convert( ord( $c ), 10, 16 ).str_pad( base_convert( ord( $c2 ), 10, 16 ), 2, 0, STR_PAD_LEFT );
88            } else{
89                $str .= '\u'.str_pad( base_convert( ord( $c2 ), 10, 16 ), 4, 0, STR_PAD_LEFT );
90            }
91        }
92        $string = strtoupper( $str );//转换为大写
93        return $this->setString( $string );
94    }
95
96    function compare( string $str, int $ignoreCase = 0 ) : int
97    {
98        if( $ignoreCase ){
99            return strcasecmp( $this->__toString(), $str );
100        } else{
101            return strcmp( $this->__toString(), $str );
102        }
103    }
104
105    function lTrim( string $charList = " \t\n\r\0\x0B" ) : SplString
106    {
107        return $this->setString( ltrim( $this->__toString(), $charList ) );
108    }
109
110    function rTrim( string $charList = " \t\n\r\0\x0B" ) : SplString
111    {
112        return $this->setString( rtrim( $this->__toString(), $charList ) );
113    }
114
115    function trim( string $charList = " \t\n\r\0\x0B" ) : SplString
116    {
117        return $this->setString( trim( $this->__toString(), $charList ) );
118    }
119
120    function pad( int $length, string $padString = null, int $pad_type = STR_PAD_RIGHT ) : SplString
121    {
122        return $this->setString( str_pad( $this->__toString(), $length, $padString, $pad_type ) );
123    }
124
125    function repeat( int $times ) : SplString
126    {
127        return $this->setString( str_repeat( $this->__toString(), $times ) );
128    }
129
130    function length() : int
131    {
132        return strlen( $this->__toString() );
133    }
134
135    function upper() : SplString
136    {
137        return $this->setString( strtoupper( $this->__toString() ) );
138    }
139
140    function lower() : SplString
141    {
142        return $this->setString( strtolower( $this->__toString() ) );
143    }
144
145    function stripTags( string $allowable_tags = null ) : SplString
146    {
147        return $this->setString( strip_tags( $this->__toString(), $allowable_tags ) );
148    }
149
150    function replace( string $find, string $replaceTo ) : SplString
151    {
152        return $this->setString( str_replace( $find, $replaceTo, $this->__toString() ) );
153    }
154
155    function between( string $startStr, string $endStr ) : SplString
156    {
157        $explode_arr = explode( $startStr, $this->__toString() );
158        if( isset( $explode_arr[1] ) ){
159            $explode_arr = explode( $endStr, $explode_arr[1] );
160            return $this->setString( $explode_arr[0] );
161        } else{
162            return $this->setString( '' );
163        }
164    }
165
166    public function regex( $regex, bool $rawReturn = false )
167    {
168        preg_match( $regex, $this->__toString(), $result );
169        if( !empty( $result ) ){
170            if( $rawReturn ){
171                return $result;
172            } else{
173                return $result[0];
174            }
175        } else{
176            return null;
177        }
178    }
179
180    public function exist( string $find, bool $ignoreCase = true ) : bool
181    {
182        if( $ignoreCase ){
183            $label = stripos( $this->__toString(), $find );
184        } else{
185            $label = strpos( $this->__toString(), $find );
186        }
187        return $label === false ? false : true;
188    }
189
190    /**
191     * 转换为烤串
192     */
193    function kebab() : SplString
194    {
195        return $this->snake( '-' );
196    }
197
198    /**
199     * 转为蛇的样子
200     * @param  string $delimiter
201     */
202    function snake( string $delimiter = '_' ) : SplString
203    {
204        $string = $this->__toString();
205        if( !ctype_lower( $string ) ){
206            $string = preg_replace( '/\s+/u', '', ucwords( $this->__toString() ) );
207            $string = $this->setString( preg_replace( '/(.)(?=[A-Z])/u', '$1'.$delimiter, $string ) );
208            $this->setString( $string );
209            $this->lower();
210        }
211        return $this;
212    }
213
214
215    /**
216     * 转为大写的大写
217     */
218    function studly() : SplString
219    {
220        $value = ucwords( str_replace( ['-', '_'], ' ', $this->__toString() ) );
221        return $this->setString( str_replace( ' ', '', $value ) );
222    }
223
224    /**
225     * 驼峰
226     *
227     */
228    function camel() : SplString
229    {
230        $this->studly();
231        return $this->setString( lcfirst( $this->__toString() ) );
232    }
233
234
235    /**
236     * 用数组逐个字符
237     * @param  string $search
238     * @param  array  $replace
239     */
240    public function replaceArray( string $search, array $replace ) : SplString
241    {
242        foreach( $replace as $value ){
243            $this->setString( $this->replaceFirst( $search, $value ) );
244        }
245        return $this;
246    }
247
248    /**
249     * 替换字符串中给定值的第一次出现。
250     * @param  string $search
251     * @param  string $replace
252     */
253    public function replaceFirst( string $search, string $replace ) : SplString
254    {
255        if( $search == '' ){
256            return $this;
257        }
258
259        $position = strpos( $this->__toString(), $search );
260
261        if( $position !== false ){
262            return $this->setString( substr_replace( $this->__toString(), $replace, $position, strlen( $search ) ) );
263        }
264
265        return $this;
266    }
267
268    /**
269     * 替换字符串中给定值的最后一次出现。
270     * @param  string $search
271     * @param  string $replace
272     */
273    public function replaceLast( string $search, string $replace ) : SplString
274    {
275        $position = strrpos( $this->__toString(), $search );
276
277        if( $position !== false ){
278            return $this->setString( substr_replace( $this->__toString(), $replace, $position, strlen( $search ) ) );
279        }
280
281        return $this;
282    }
283
284    /**
285     * 以一个给定值的单一实例开始一个字符串
286     *
287     * @param  string $prefix
288     */
289    public function start( string $prefix ) : SplString
290    {
291        $quoted = preg_quote( $prefix, '/' );
292        return $this->setString( $prefix.preg_replace( '/^(?:'.$quoted.')+/u', '', $this->__toString() ) );
293    }
294
295    /**
296     * 在给定的值之后返回字符串的其余部分。
297     *
298     * @param  string $search
299     */
300    function after( string $search ) : SplString
301    {
302        if( $search === '' ){
303            return $this;
304        } else{
305            return $this->setString( array_reverse( explode( $search, $this->__toString(), 2 ) )[0] );
306        }
307    }
308
309    /**
310     * 在给定的值之前获取字符串的一部分
311     *
312     * @param  string $search
313     */
314    function before( string $search ) : SplString
315    {
316        if( $search === '' ){
317            return $this;
318        } else{
319            return $this->setString( explode( $search, $this->__toString() )[0] );
320        }
321    }
322
323    /**
324     * 确定给定的字符串是否以给定的子字符串结束
325     *
326     * @param  string       $haystack
327     * @param  string|array $needles
328     * @return bool
329     */
330    public function endsWith( $needles ) : bool
331    {
332        foreach( (array)$needles as $needle ){
333            if( substr( $this->__toString(), - strlen( $needle ) ) === (string)$needle ){
334                return true;
335            }
336        }
337        return false;
338    }
339
340    /**
341     * 确定给定的字符串是否从给定的子字符串开始
342     *
343     * @param  string       $haystack
344     * @param  string|array $needles
345     * @return bool
346     */
347    public function startsWith( $needles ) : bool
348    {
349        foreach( (array)$needles as $needle ){
350            if( $needle !== '' && substr( $this->__toString(), 0, strlen( $needle ) ) === (string)$needle ){
351                return true;
352            }
353        }
354        return false;
355    }
356}