1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace StringObject; |
4
|
|
|
|
5
|
|
|
class StrObj implements \ArrayAccess, \Countable, \Iterator |
6
|
|
|
{ |
7
|
|
|
// CONSTANTS |
8
|
|
|
|
9
|
|
|
const NORMAL = 0; |
10
|
|
|
const START = 0; |
11
|
|
|
const END = 1; |
12
|
|
|
const BOTH_ENDS = 2; |
13
|
|
|
const CASE_INSENSITIVE = 4; |
14
|
|
|
const REVERSE = 8; |
15
|
|
|
const EXACT_POSITION = 16; |
16
|
|
|
const CURRENT_LOCALE = 32; |
17
|
|
|
const NATURAL_ORDER = 64; |
18
|
|
|
const FIRST_N = 128; |
19
|
|
|
const C_STYLE = 256; |
20
|
|
|
const META = 512; |
21
|
|
|
const LAZY = 1024; |
22
|
|
|
const GREEDY = 2048; |
23
|
|
|
|
24
|
|
|
// STATIC PROPERTIES |
25
|
|
|
|
26
|
|
|
protected static $asciimap = [ |
27
|
|
|
'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', |
28
|
|
|
'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', |
29
|
|
|
'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', |
30
|
|
|
'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ'], |
31
|
|
|
'b' => ['б', 'β', 'Ъ', 'Ь', 'ب'], |
32
|
|
|
'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ'], |
33
|
|
|
'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض'], |
34
|
|
|
'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', |
35
|
|
|
'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', |
36
|
|
|
'έ', 'е', 'ё', 'э', 'є', 'ə'], |
37
|
|
|
'f' => ['ф', 'φ', 'ف'], |
38
|
|
|
'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ج'], |
39
|
|
|
'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه'], |
40
|
|
|
'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', |
41
|
|
|
'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', |
42
|
|
|
'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и'], |
43
|
|
|
'j' => ['ĵ', 'ј', 'Ј'], |
44
|
|
|
'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك'], |
45
|
|
|
'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل'], |
46
|
|
|
'm' => ['м', 'μ', 'م'], |
47
|
|
|
'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن'], |
48
|
|
|
'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', |
49
|
|
|
'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', |
50
|
|
|
'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ'], |
51
|
|
|
'p' => ['п', 'π'], |
52
|
|
|
'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر'], |
53
|
|
|
's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص'], |
54
|
|
|
't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط'], |
55
|
|
|
'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', |
56
|
|
|
'ů', 'ű', 'ŭ', 'ų', 'µ', 'у'], |
57
|
|
|
'v' => ['в'], |
58
|
|
|
'w' => ['ŵ', 'ω', 'ώ'], |
59
|
|
|
'x' => ['χ'], |
60
|
|
|
'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي'], |
61
|
|
|
'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز'], |
62
|
|
|
'aa' => ['ع'], |
63
|
|
|
'ae' => ['ä', 'æ'], |
64
|
|
|
'ch' => ['ч'], |
65
|
|
|
'dj' => ['ђ', 'đ'], |
66
|
|
|
'dz' => ['џ'], |
67
|
|
|
'gh' => ['غ'], |
68
|
|
|
'kh' => ['х', 'خ'], |
69
|
|
|
'lj' => ['љ'], |
70
|
|
|
'nj' => ['њ'], |
71
|
|
|
'oe' => ['ö', 'œ'], |
72
|
|
|
'ps' => ['ψ'], |
73
|
|
|
'sh' => ['ш'], |
74
|
|
|
'shch' => ['щ'], |
75
|
|
|
'ss' => ['ß'], |
76
|
|
|
'th' => ['þ', 'ث', 'ذ', 'ظ'], |
77
|
|
|
'ts' => ['ц'], |
78
|
|
|
'ue' => ['ü'], |
79
|
|
|
'ya' => ['я'], |
80
|
|
|
'yu' => ['ю'], |
81
|
|
|
'zh' => ['ж'], |
82
|
|
|
'(c)' => ['©'], |
83
|
|
|
'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', |
84
|
|
|
'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', |
85
|
|
|
'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', |
86
|
|
|
'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А'], |
87
|
|
|
'B' => ['Б', 'Β'], |
88
|
|
|
'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'], |
89
|
|
|
'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'], |
90
|
|
|
'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', |
91
|
|
|
'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', |
92
|
|
|
'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə'], |
93
|
|
|
'F' => ['Ф', 'Φ'], |
94
|
|
|
'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'], |
95
|
|
|
'H' => ['Η', 'Ή'], |
96
|
|
|
'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', |
97
|
|
|
'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', |
98
|
|
|
'І', 'Ї'], |
99
|
|
|
'K' => ['К', 'Κ'], |
100
|
|
|
'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ'], |
101
|
|
|
'M' => ['М', 'Μ'], |
102
|
|
|
'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'], |
103
|
|
|
'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', |
104
|
|
|
'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', |
105
|
|
|
'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө'], |
106
|
|
|
'P' => ['П', 'Π'], |
107
|
|
|
'R' => ['Ř', 'Ŕ', 'Р', 'Ρ'], |
108
|
|
|
'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'], |
109
|
|
|
'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'], |
110
|
|
|
'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', |
111
|
|
|
'Ů', 'Ű', 'Ŭ', 'Ų', 'У'], |
112
|
|
|
'V' => ['В'], |
113
|
|
|
'W' => ['Ω', 'Ώ'], |
114
|
|
|
'X' => ['Χ'], |
115
|
|
|
'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ'], |
116
|
|
|
'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ'], |
117
|
|
|
'AE' => ['Ä', 'Æ'], |
118
|
|
|
'CH' => ['Ч'], |
119
|
|
|
'DJ' => ['Ђ'], |
120
|
|
|
'DZ' => ['Џ'], |
121
|
|
|
'KH' => ['Х'], |
122
|
|
|
'LJ' => ['Љ'], |
123
|
|
|
'NJ' => ['Њ'], |
124
|
|
|
'OE' => ['Ö'], |
125
|
|
|
'PS' => ['Ψ'], |
126
|
|
|
'SH' => ['Ш'], |
127
|
|
|
'SHCH' => ['Щ'], |
128
|
|
|
'SS' => ['ẞ'], |
129
|
|
|
'TH' => ['Þ'], |
130
|
|
|
'TS' => ['Ц'], |
131
|
|
|
'UE' => ['Ü'], |
132
|
|
|
'YA' => ['Я'], |
133
|
|
|
'YU' => ['Ю'], |
134
|
|
|
'ZH' => ['Ж'], |
135
|
|
|
' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", |
136
|
|
|
"\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", |
137
|
|
|
"\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", |
138
|
|
|
"\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"], |
139
|
|
|
]; |
140
|
|
|
|
141
|
|
|
// PROPERTIES |
142
|
|
|
|
143
|
|
|
protected $raw; |
144
|
|
|
protected $token = false; |
145
|
|
|
protected $caret = 0; |
146
|
|
|
|
147
|
|
|
// MAGIC METHODS |
148
|
|
|
|
149
|
|
|
public function __construct($thing) |
150
|
|
|
{ |
151
|
|
|
self::testStringableObject($thing); |
152
|
|
|
|
153
|
|
|
if (\is_array($thing)) { |
154
|
|
|
throw new \InvalidArgumentException('Unsure of how to convert array to string'); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
$this->raw = (string) $thing; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @return mixed |
162
|
|
|
*/ |
163
|
|
|
public function __get($name) |
164
|
|
|
{ |
165
|
|
|
return $this->$name; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @return string |
170
|
|
|
*/ |
171
|
|
|
public function __toString() |
172
|
|
|
{ |
173
|
|
|
return $this->raw; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
View Code Duplication |
public function toArray($delim = '', $limit = null) |
|
|
|
|
177
|
|
|
{ |
178
|
|
|
if (empty($delim)) { |
179
|
|
|
return \str_split($this->raw); |
180
|
|
|
} |
181
|
|
|
if (is_int($delim)) { |
182
|
|
|
return \str_split($this->raw, $delim); |
183
|
|
|
} |
184
|
|
|
if ($limit === null) { |
185
|
|
|
return \explode($delim, $this->raw); |
186
|
|
|
} |
187
|
|
|
return \explode($delim, $this->raw, $limit); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
// INFORMATIONAL METHODS |
191
|
|
|
|
192
|
|
|
public function charAt($offset) |
193
|
|
|
{ |
194
|
|
|
return new self($this->raw{$offset}); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @param integer $offset |
199
|
|
|
*/ |
200
|
|
|
public function charCodeAt($offset) |
201
|
|
|
{ |
202
|
|
|
return \ord($this->raw{$offset}); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
public function compareTo($str, $mode = self::NORMAL, $length = 1) |
206
|
|
|
{ |
207
|
|
|
$modemap = [ |
208
|
|
|
self::NORMAL => 'strcmp', |
209
|
|
|
self::CASE_INSENSITIVE => 'strcasecmp', |
210
|
|
|
self::CURRENT_LOCALE => 'strcoll', |
211
|
|
|
self::NATURAL_ORDER => 'strnatcmp', |
212
|
|
|
(self::NATURAL_ORDER | self::CASE_INSENSITIVE) => 'strnatcasecmp', |
213
|
|
|
self::FIRST_N => 'strncmp', |
214
|
|
|
(self::FIRST_N | self::CASE_INSENSITIVE) => 'strncasecmp', |
215
|
|
|
]; |
216
|
|
|
|
217
|
|
|
if ($mode & self::FIRST_N) { |
218
|
|
|
return \call_user_func($modemap[$mode], $this->raw, $str, $length); |
219
|
|
|
} |
220
|
|
|
return \call_user_func($modemap[$mode], $this->raw, $str); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
public function indexOf($needle, $offset = 0, $mode = self::NORMAL) |
224
|
|
|
{ |
225
|
|
|
// strip out bits we don't understand |
226
|
|
|
$mode &= (self::REVERSE | self::CASE_INSENSITIVE); |
227
|
|
|
|
228
|
|
|
$modemap = [ |
229
|
|
|
self::NORMAL => 'strpos', |
230
|
|
|
self::CASE_INSENSITIVE => 'stripos', |
231
|
|
|
self::REVERSE => 'strrpos', |
232
|
|
|
(self::REVERSE | self::CASE_INSENSITIVE) => 'strripos', |
233
|
|
|
]; |
234
|
|
|
return \call_user_func($modemap[$mode], $this->raw, $needle, $offset); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
public function length() |
238
|
|
|
{ |
239
|
|
|
return \strlen($this->raw); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
// MODIFYING METHODS |
243
|
|
|
|
244
|
|
|
public function append($str) |
245
|
|
|
{ |
246
|
|
|
return new self($this->raw . $str); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
public function asciify($removeUnsupported = true) |
250
|
|
|
{ |
251
|
|
|
$str = $this->raw; |
252
|
|
|
foreach (self::$asciimap as $key => $value) { |
253
|
|
|
$str = \str_replace($value, $key, $str); |
254
|
|
|
} |
255
|
|
|
if ($removeUnsupported) { |
256
|
|
|
$str = \preg_replace('/[^\x20-\x7E]/u', '', $str); |
257
|
|
|
} |
258
|
|
|
return new self($str); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
public function chunk($length = 76, $ending = "\r\n") |
262
|
|
|
{ |
263
|
|
|
return new self(\chunk_split($this->raw, $length, $ending)); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
public function concat($str) |
267
|
|
|
{ |
268
|
|
|
return $this->append($str); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
public function escape($mode = self::NORMAL, $charlist = '') |
272
|
|
|
{ |
273
|
|
|
$modemap = [ |
274
|
|
|
self::NORMAL => 'addslashes', |
275
|
|
|
self::C_STYLE => 'addcslashes', |
276
|
|
|
self::META => 'quotemeta', |
277
|
|
|
]; |
278
|
|
|
if ($mode === self::C_STYLE) { |
279
|
|
|
return new self(\call_user_func($modemap[$mode], $this->raw, $charlist)); |
280
|
|
|
} |
281
|
|
|
return new self(\call_user_func($modemap[$mode], $this->raw)); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
public function insertAt($str, $offset) |
285
|
|
|
{ |
286
|
|
|
return $this->replaceSubstr($str, $offset, 0); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
public function nextToken($delim) |
290
|
|
|
{ |
291
|
|
|
if ($this->token) { |
292
|
|
|
return new self(\strtok($delim)); |
293
|
|
|
} |
294
|
|
|
$this->token = true; |
295
|
|
|
return new self(\strtok($this->raw, $delim)); |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
public function pad($newlength, $padding = ' ', $mode = self::END) |
299
|
|
|
{ |
300
|
|
|
return new self(\str_pad($this->raw, $newlength, $padding, $mode)); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
public function prepend($str) |
304
|
|
|
{ |
305
|
|
|
return new self($str . $this->raw); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
public function remove($str, $mode = self::NORMAL) |
309
|
|
|
{ |
310
|
|
|
return $this->replace($str, '', $mode); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
public function removeSubstr($start, $length = null) |
314
|
|
|
{ |
315
|
|
|
return $this->replaceSubstr('', $start, $length); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
public function repeat($times) |
319
|
|
|
{ |
320
|
|
|
return new self(\str_repeat($this->raw, $times)); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* @param string $replace |
325
|
|
|
*/ |
326
|
|
|
public function replace($search, $replace, $mode = self::NORMAL) |
327
|
|
|
{ |
328
|
|
|
if ($mode & self::CASE_INSENSITIVE) { |
329
|
|
|
return new self(\str_ireplace($search, $replace, $this->raw)); |
330
|
|
|
} |
331
|
|
|
return new self(\str_replace($search, $replace, $this->raw)); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
public function replaceSubstr($replacement, $start, $length = null) |
335
|
|
|
{ |
336
|
|
|
if ($length === null) { |
337
|
|
|
$length = $this->length(); |
338
|
|
|
} |
339
|
|
|
return new self(\substr_replace($this->raw, $replacement, $start, $length)); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
public function resetToken() |
343
|
|
|
{ |
344
|
|
|
$this->token = false; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
public function reverse() |
348
|
|
|
{ |
349
|
|
|
return new self(\strrev($this->raw)); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
public function shuffle() |
353
|
|
|
{ |
354
|
|
|
return new self(\str_shuffle($this->raw)); |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
public function substr($start, $length = 'omitted') |
358
|
|
|
{ |
359
|
|
|
if ($length === 'omitted') { |
360
|
|
|
return new self(\substr($this->raw, $start)); |
361
|
|
|
} |
362
|
|
|
return new self(\substr($this->raw, $start, $length)); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
public function times($times) |
366
|
|
|
{ |
367
|
|
|
return $this->repeat($times); |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
public function translate($search, $replace = '') |
371
|
|
|
{ |
372
|
|
|
if (is_array($search)) { |
373
|
|
|
return new self(\strtr($this->raw, $search)); |
374
|
|
|
} |
375
|
|
|
return new self(\strtr($this->raw, $search, $replace)); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
public function trim($mask = " \t\n\r\0\x0B", $mode = self::BOTH_ENDS) |
379
|
|
|
{ |
380
|
|
|
$modemap = [ |
381
|
|
|
self::START => 'ltrim', |
382
|
|
|
self::END => 'rtrim', |
383
|
|
|
self::BOTH_ENDS => 'trim', |
384
|
|
|
]; |
385
|
|
|
return new self(\call_user_func($modemap[$mode], $this->raw, $mask)); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
public function unescape($mode = self::NORMAL) |
389
|
|
|
{ |
390
|
|
|
$modemap = [ |
391
|
|
|
self::NORMAL => 'stripslashes', |
392
|
|
|
self::C_STYLE => 'stripcslashes', |
393
|
|
|
self::META => 'stripslashes', |
394
|
|
|
]; |
395
|
|
|
return new self(\call_user_func($modemap[$mode], $this->raw)); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
public function uuDecode() |
399
|
|
|
{ |
400
|
|
|
return new self(\convert_uudecode($this->raw)); |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
public function uuEncode() |
404
|
|
|
{ |
405
|
|
|
return new self(\convert_uuencode($this->raw)); |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
public function wordwrap($width = 75, $break = "\n") |
409
|
|
|
{ |
410
|
|
|
return new self(\wordwrap($this->raw, $width, $break, false)); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
public function wordwrapBreaking($width = 75, $break = "\n") |
414
|
|
|
{ |
415
|
|
|
return new self(\wordwrap($this->raw, $width, $break, true)); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
// TESTING METHODS |
419
|
|
|
|
420
|
|
|
public function contains($needle, $offset = 0, $mode = self::NORMAL) |
421
|
|
|
{ |
422
|
|
|
if ($mode & self::EXACT_POSITION) { |
423
|
|
|
return ($this->indexOf($needle, $offset, $mode) === $offset); |
424
|
|
|
} |
425
|
|
|
return ($this->indexOf($needle, $offset, $mode) !== false); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
public function countSubstr($needle, $offset = 0, $length = null) |
429
|
|
|
{ |
430
|
|
|
if ($length === null) { |
431
|
|
|
return \substr_count($this->raw, $needle, $offset); |
432
|
|
|
} |
433
|
|
|
return \substr_count($this->raw, $needle, $offset, $length); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
public function endsWith($str, $mode = self::NORMAL) |
437
|
|
|
{ |
438
|
|
|
$mode &= self::CASE_INSENSITIVE; |
439
|
|
|
$offset = $this->length() - \strlen($str); |
440
|
|
|
return $this->contains($str, $offset, $mode | self::EXACT_POSITION | self::REVERSE); |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
public function equals($str) |
444
|
|
|
{ |
445
|
|
|
self::testStringableObject($str); |
446
|
|
|
|
447
|
|
|
$str = (string) $str; |
448
|
|
|
return ($str == $this->raw); |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
public function isAscii() |
452
|
|
|
{ |
453
|
|
|
$len = $this->length(); |
454
|
|
|
|
455
|
|
|
for ($i = 0; $i < $len; $i++) { |
456
|
|
|
if ($this->charCodeAt($i) >= 128) { |
457
|
|
|
return false; |
458
|
|
|
} |
459
|
|
|
} |
460
|
|
|
return true; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
public function isEmpty() |
464
|
|
|
{ |
465
|
|
|
return empty($this->raw); |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
public function startsWith($str, $mode = self::NORMAL) |
469
|
|
|
{ |
470
|
|
|
$mode &= self::CASE_INSENSITIVE; |
471
|
|
|
return $this->contains($str, 0, $mode | self::EXACT_POSITION); |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
// INTERFACE IMPLEMENTATION METHODS |
475
|
|
|
|
476
|
|
|
public function count() |
477
|
|
|
{ |
478
|
|
|
return \strlen($this->raw); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
public function current() |
482
|
|
|
{ |
483
|
|
|
return $this->raw[$this->caret]; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
public function key() |
487
|
|
|
{ |
488
|
|
|
return $this->caret; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
public function next() |
492
|
|
|
{ |
493
|
|
|
$this->caret++; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
public function rewind() |
497
|
|
|
{ |
498
|
|
|
$this->caret = 0; |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
public function valid() |
502
|
|
|
{ |
503
|
|
|
return ($this->caret < \strlen($this->raw)); |
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
public function offsetExists($offset) |
507
|
|
|
{ |
508
|
|
|
$offset = (int) $offset; |
509
|
|
|
return ($offset >= 0 && $offset < \strlen($this->raw)); |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
public function offsetGet($offset) |
513
|
|
|
{ |
514
|
|
|
return $this->raw{$offset}; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
public function offsetSet($offset, $value) |
518
|
|
|
{ |
519
|
|
|
throw new \LogicException('Cannot assign '.$value.' to immutable StrObj instance at index '.$offset); |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
public function offsetUnset($offset) |
523
|
|
|
{ |
524
|
|
|
throw new \LogicException('Cannot unset index '.$offset.' on immutable StrObj instance'); |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
// PRIVATE STATIC FUNCTIONS |
528
|
|
|
|
529
|
|
|
protected static function testStringableObject($thing) |
530
|
|
|
{ |
531
|
|
|
if (\is_object($thing) && !\method_exists($thing, '__toString')) { |
532
|
|
|
throw new \InvalidArgumentException( |
533
|
|
|
'Parameter is an object that does not implement __toString() method' |
534
|
|
|
); |
535
|
|
|
} |
536
|
|
|
} |
537
|
|
|
} |
538
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.