|
14 | 14 | use Toolkit\Stdlib\Str\Traits\StringCheckHelperTrait; |
15 | 15 | use Toolkit\Stdlib\Str\Traits\StringLengthHelperTrait; |
16 | 16 | use Toolkit\Stdlib\Str\Traits\StringSplitHelperTrait; |
| 17 | +use Toolkit\Stdlib\Str\Traits\StringTruncateHelperTrait; |
17 | 18 | use Toolkit\Stdlib\Util\UUID; |
18 | 19 | use function array_merge; |
19 | 20 | use function array_slice; |
@@ -62,6 +63,7 @@ abstract class StringHelper |
62 | 63 | use StringCheckHelperTrait; |
63 | 64 | use StringLengthHelperTrait; |
64 | 65 | use StringSplitHelperTrait; |
| 66 | + use StringTruncateHelperTrait; |
65 | 67 |
|
66 | 68 | /** |
67 | 69 | * @param string $str |
@@ -192,302 +194,11 @@ public static function genUid(int $length = 7): string |
192 | 194 | * |
193 | 195 | * @return UUID |
194 | 196 | */ |
195 | | - public static function genUUID($version = 1, $node = null, $ns = null) |
| 197 | + public static function genUUID(int $version = 1, $node = null, $ns = null) |
196 | 198 | { |
197 | 199 | return UUID::generate($version, $node, $ns); |
198 | 200 | } |
199 | 201 |
|
200 | | - //////////////////////////////////////////////////////////////////////// |
201 | | - /// Truncate |
202 | | - //////////////////////////////////////////////////////////////////////// |
203 | | - |
204 | | - /** |
205 | | - * @param string $str |
206 | | - * @param int $start |
207 | | - * @param int|null $length |
208 | | - * @param string $encoding |
209 | | - * |
210 | | - * @return bool|string |
211 | | - */ |
212 | | - public static function substr(string $str, int $start, int $length = null, string $encoding = 'utf-8') |
213 | | - { |
214 | | - if (function_exists('mb_substr')) { |
215 | | - return mb_substr($str, $start, ($length === null ? self::strlen($str) : (int)$length), $encoding); |
216 | | - } |
217 | | - |
218 | | - return substr($str, $start, ($length === null ? self::strlen($str) : (int)$length)); |
219 | | - } |
220 | | - |
221 | | - /** |
222 | | - * @from web |
223 | | - * utf-8编码下截取中文字符串,参数可以参照substr函数 |
224 | | - * |
225 | | - * @param string $str 要进行截取的字符串 |
226 | | - * @param int $start 要进行截取的开始位置,负数为反向截取 |
227 | | - * @param int $end 要进行截取的长度 |
228 | | - * |
229 | | - * @return string |
230 | | - */ |
231 | | - public static function utf8SubStr(string $str, int $start = 0, int $end = null): string |
232 | | - { |
233 | | - if (empty($str)) { |
234 | | - return ''; |
235 | | - } |
236 | | - |
237 | | - if (function_exists('mb_substr')) { |
238 | | - if (func_num_args() >= 3) { |
239 | | - $end = func_get_arg(2); |
240 | | - |
241 | | - return mb_substr($str, $start, $end, 'utf-8'); |
242 | | - } |
243 | | - |
244 | | - mb_internal_encoding('UTF-8'); |
245 | | - |
246 | | - return mb_substr($str, $start); |
247 | | - } |
248 | | - |
249 | | - $null = ''; |
250 | | - preg_match_all('/./u', $str, $ar); |
251 | | - |
252 | | - if (func_num_args() >= 3) { |
253 | | - $end = func_get_arg(2); |
254 | | - return implode($null, array_slice($ar[0], $start, $end)); |
255 | | - } |
256 | | - |
257 | | - return implode($null, array_slice($ar[0], $start)); |
258 | | - } |
259 | | - |
260 | | - /** |
261 | | - * @from web |
262 | | - * 中文截取,支持gb2312,gbk,utf-8,big5 * |
263 | | - * |
264 | | - * @param string $str 要截取的字串 |
265 | | - * @param int $start 截取起始位置 |
266 | | - * @param int $length 截取长度 |
267 | | - * @param string $charset utf-8|gb2312|gbk|big5 编码 |
268 | | - * @param bool $suffix 是否加尾缀 |
269 | | - * |
270 | | - * @return string |
271 | | - */ |
272 | | - public static function zhSubStr($str, $start = 0, $length = 0, $charset = 'utf-8', $suffix = true): string |
273 | | - { |
274 | | - if (function_exists('mb_substr')) { |
275 | | - if (mb_strlen($str, $charset) <= $length) { |
276 | | - return $str; |
277 | | - } |
278 | | - |
279 | | - $slice = mb_substr($str, $start, $length, $charset); |
280 | | - } else { |
281 | | - $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; |
282 | | - $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; |
283 | | - $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; |
284 | | - $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; |
285 | | - |
286 | | - preg_match_all($re[$charset], $str, $match); |
287 | | - if (count($match[0]) <= $length) { |
288 | | - return $str; |
289 | | - } |
290 | | - |
291 | | - $slice = implode('', array_slice($match[0], $start, $length)); |
292 | | - } |
293 | | - |
294 | | - return (bool)$suffix ? $slice . '…' : $slice; |
295 | | - } |
296 | | - |
297 | | - /** |
298 | | - * Truncate strings |
299 | | - * |
300 | | - * @param string $str |
301 | | - * @param int $maxLength Max length |
302 | | - * @param string $suffix Suffix optional |
303 | | - * |
304 | | - * @return string $str truncated |
305 | | - */ |
306 | | - /* CAUTION : Use it only on module hookEvents. |
307 | | - ** For other purposes use the smarty function instead */ |
308 | | - public static function truncate(string $str, $maxLength, $suffix = '...'): string |
309 | | - { |
310 | | - if (self::strlen($str) <= $maxLength) { |
311 | | - return $str; |
312 | | - } |
313 | | - |
314 | | - $str = utf8_decode($str); |
315 | | - |
316 | | - return utf8_encode(substr($str, 0, $maxLength - self::strlen($suffix)) . $suffix); |
317 | | - } |
318 | | - |
319 | | - /** |
320 | | - * 字符截断输出 |
321 | | - * |
322 | | - * @param string $str |
323 | | - * @param int $start |
324 | | - * @param null|int $length |
325 | | - * |
326 | | - * @return string |
327 | | - */ |
328 | | - public static function truncate2(string $str, int $start, int $length = null): string |
329 | | - { |
330 | | - if (!$length) { |
331 | | - $length = $start; |
332 | | - $start = 0; |
333 | | - } |
334 | | - |
335 | | - if (strlen($str) <= $length) { |
336 | | - return $str; |
337 | | - } |
338 | | - |
339 | | - if (function_exists('mb_substr')) { |
340 | | - $str = mb_substr(strip_tags($str), $start, $length, 'utf-8'); |
341 | | - } else { |
342 | | - $str = substr($str, $start, $length) . '...'; |
343 | | - } |
344 | | - |
345 | | - return $str; |
346 | | - } |
347 | | - |
348 | | - /** |
349 | | - * Copied from CakePHP String utility file |
350 | | - * |
351 | | - * @param string $text |
352 | | - * @param int $length |
353 | | - * @param array $options |
354 | | - * |
355 | | - * @return bool|string |
356 | | - */ |
357 | | - public static function truncate3(string $text, int $length = 120, array $options = []) |
358 | | - { |
359 | | - $default = [ |
360 | | - 'ellipsis' => '...', |
361 | | - 'exact' => true, |
362 | | - 'html' => true |
363 | | - ]; |
364 | | - |
365 | | - $options = array_merge($default, $options); |
366 | | - $ellipsis = $options['ellipsis']; |
367 | | - $exact = $options['exact']; |
368 | | - $html = $options['html']; |
369 | | - |
370 | | - /** |
371 | | - * @var string $ellipsis |
372 | | - * @var bool $exact |
373 | | - * @var bool $html |
374 | | - */ |
375 | | - if ($html) { |
376 | | - if (self::strlen(\preg_replace('/<.*?>/', '', $text)) <= $length) { |
377 | | - return $text; |
378 | | - } |
379 | | - |
380 | | - $total_length = self::strlen(strip_tags($ellipsis)); |
381 | | - $open_tags = $tags = []; |
382 | | - $truncate = ''; |
383 | | - preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); |
384 | | - |
385 | | - foreach ($tags as $tag) { |
386 | | - if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/', $tag[2])) { |
387 | | - if (preg_match('/<[\w]+[^>]*>/', $tag[0])) { |
388 | | - array_unshift($open_tags, $tag[2]); |
389 | | - } elseif (preg_match('/<\/([\w]+)[^>]*>/', $tag[0], $close_tag)) { |
390 | | - $pos = array_search($close_tag[1], $open_tags, true); |
391 | | - if ($pos !== false) { |
392 | | - array_splice($open_tags, $pos, 1); |
393 | | - } |
394 | | - } |
395 | | - } |
396 | | - $truncate .= $tag[1]; |
397 | | - $content_length = self::strlen(preg_replace( |
398 | | - '/&[0-9a-z]{2,8};|&#[\d]{1,7};|&#x[0-9a-f]{1,6};/i', |
399 | | - ' ', |
400 | | - $tag[3] |
401 | | - )); |
402 | | - |
403 | | - if ($content_length + $total_length > $length) { |
404 | | - $left = $length - $total_length; |
405 | | - $entities_length = 0; |
406 | | - |
407 | | - if (preg_match_all( |
408 | | - '/&[0-9a-z]{2,8};|&#[\d]{1,7};|&#x[0-9a-f]{1,6};/i', |
409 | | - $tag[3], |
410 | | - $entities, |
411 | | - PREG_OFFSET_CAPTURE |
412 | | - ) |
413 | | - ) { |
414 | | - foreach ((array)$entities[0] as $entity) { |
415 | | - if ($entity[1] + 1 - $entities_length <= $left) { |
416 | | - $left--; |
417 | | - $entities_length += self::strlen($entity[0]); |
418 | | - } else { |
419 | | - break; |
420 | | - } |
421 | | - } |
422 | | - } |
423 | | - |
424 | | - $truncate .= self::substr($tag[3], 0, $left + $entities_length); |
425 | | - break; |
426 | | - } |
427 | | - |
428 | | - $truncate .= $tag[3]; |
429 | | - $total_length += $content_length; |
430 | | - |
431 | | - if ($total_length >= $length) { |
432 | | - break; |
433 | | - } |
434 | | - } |
435 | | - } else { |
436 | | - if (self::strlen($text) <= $length) { |
437 | | - return $text; |
438 | | - } |
439 | | - |
440 | | - $truncate = self::substr($text, 0, $length - self::strlen($ellipsis)); |
441 | | - } |
442 | | - |
443 | | - $open_tags = null; |
444 | | - |
445 | | - if (!$exact) { |
446 | | - $spacepos = self::strrpos($truncate, ' '); |
447 | | - if ($html) { |
448 | | - $truncate_check = self::substr($truncate, 0, $spacepos); |
449 | | - $last_open_tag = self::strrpos($truncate_check, '<'); |
450 | | - $last_close_tag = self::strrpos($truncate_check, '>'); |
451 | | - |
452 | | - if ($last_open_tag > $last_close_tag) { |
453 | | - preg_match_all('/<[\w]+[^>]*>/', $truncate, $last_tag_matches); |
454 | | - $last_tag = array_pop($last_tag_matches[0]); |
455 | | - $spacepos = self::strrpos($truncate, $last_tag) + self::strlen($last_tag); |
456 | | - } |
457 | | - |
458 | | - $bits = self::substr($truncate, $spacepos); |
459 | | - preg_match_all('/<\/([a-z]+)>/', $bits, $dropped_tags, PREG_SET_ORDER); |
460 | | - |
461 | | - /** @var array $dropped_tags */ |
462 | | - if (!empty($dropped_tags)) { |
463 | | - if (!empty($open_tags)) { |
464 | | - foreach ($dropped_tags as $closing_tag) { |
465 | | - if (!in_array($closing_tag[1], $open_tags, true)) { |
466 | | - array_unshift($open_tags, $closing_tag[1]); |
467 | | - } |
468 | | - } |
469 | | - } else { |
470 | | - foreach ($dropped_tags as $closing_tag) { |
471 | | - $open_tags[] = $closing_tag[1]; |
472 | | - } |
473 | | - } |
474 | | - } |
475 | | - } |
476 | | - |
477 | | - $truncate = self::substr($truncate, 0, $spacepos); |
478 | | - } |
479 | | - |
480 | | - $truncate .= $ellipsis; |
481 | | - |
482 | | - if ($html && $open_tags) { |
483 | | - foreach ((array)$open_tags as $tag) { |
484 | | - $truncate .= '</' . $tag . '>'; |
485 | | - } |
486 | | - } |
487 | | - |
488 | | - return $truncate; |
489 | | - } |
490 | | - |
491 | 202 | //////////////////////////////////////////////////////////////////////// |
492 | 203 | /// Format |
493 | 204 | //////////////////////////////////////////////////////////////////////// |
@@ -597,4 +308,26 @@ public static function deleteStripSpace($fileName, $type = 0) |
597 | 308 |
|
598 | 309 | return preg_replace($preg_arr, '', $data); |
599 | 310 | } |
| 311 | + |
| 312 | + //////////////////////////////////////////////////////////// |
| 313 | + /// Other |
| 314 | + //////////////////////////////////////////////////////////// |
| 315 | + |
| 316 | + /** |
| 317 | + * @param string $arg |
| 318 | + * |
| 319 | + * @return string |
| 320 | + */ |
| 321 | + public static function shellQuote(string $arg): string |
| 322 | + { |
| 323 | + $quote = ''; |
| 324 | + |
| 325 | + if (strpos($arg, '"') !== false) { |
| 326 | + $quote = "'"; |
| 327 | + } elseif ($arg === '' || strpos($arg, "'") !== false || strpos($arg, ' ') !== false) { |
| 328 | + $quote = '"'; |
| 329 | + } |
| 330 | + |
| 331 | + return $quote ? $arg : "$quote{$arg}$quote"; |
| 332 | + } |
600 | 333 | } |
0 commit comments