Created
September 12, 2019 18:38
-
-
Save ItsShadowl/286131a0a42eba528b802263e598d0fd to your computer and use it in GitHub Desktop.
String class in PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* This file is part of the Symfony package. | |
* | |
* (c) Fabien Potencier <fabien@symfony.com> | |
* | |
* For the full copyright and license information, please view the LICENSE | |
* file that was distributed with this source code. | |
*/ | |
namespace Stringie; | |
use \Exception\RuntimeException; | |
use \Exception\InvalidArgumentException; | |
/** | |
* @author Nicolas Grekas <p@tchwork.com> | |
* @author Hugo Hamon <hugohamon@neuf.fr> | |
* @author Olumide Samson <noobshow@gmail.com> | |
* | |
* @throws \Exception\InvalidArgumentException | |
* @throws \Exception\RuntimeException | |
*/ | |
class Stringie | |
{ | |
public function __construct(string $string = '', string $locale = null) | |
{ | |
$this->string = $string; | |
if (null !== $locale) { | |
$this->locale = $this->withLocale($locale)->locale; | |
} | |
} | |
public static function random(int $length = 16): self | |
{ | |
$string = ''; | |
do { | |
$string .= str_replace(['/', '+', '='], '', base64_encode(random_bytes($length))); | |
} while (\strlen($string) < $length); | |
return new static(substr($string, 0, $length)); | |
} | |
public function after(string $needle, bool $includeNeedle = false): self | |
{ | |
$str = clone $this; | |
if ('' === $needle) { | |
$str->string = ''; | |
} else { | |
$i = $this->ignoreCase ? stripos($this->string, $needle) : strpos($this->string, $needle); | |
$str->string = false === $i ? '' : substr($str->string, $i + ($includeNeedle ? 0 : \strlen($needle))); | |
} | |
return $str; | |
} | |
public function afterLast(string $needle, bool $includeNeedle = false): self | |
{ | |
$str = clone $this; | |
if ('' === $needle) { | |
$str->string = ''; | |
} else { | |
$i = $this->ignoreCase ? strripos($this->string, $needle) : strrpos($this->string, $needle); | |
$str->string = false === $i ? '' : substr($str->string, $i + ($includeNeedle ? 0 : \strlen($needle))); | |
} | |
return $str; | |
} | |
public function append(string ...$suffix): self | |
{ | |
$str = clone $this; | |
$str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : implode('', $suffix); | |
return $str; | |
} | |
public function before(string $needle, bool $includeNeedle = false): self | |
{ | |
$str = clone $this; | |
if ('' === $needle) { | |
$str->string = ''; | |
} else { | |
$i = $this->ignoreCase ? stripos($this->string, $needle) : strpos($this->string, $needle); | |
$str->string = false === $i ? '' : substr($str->string, 0, $i + ($includeNeedle ? \strlen($needle) : 0)); | |
} | |
return $str; | |
} | |
public function beforeLast(string $needle, bool $includeNeedle = false): self | |
{ | |
$str = clone $this; | |
if ('' === $needle) { | |
$str->string = ''; | |
} else { | |
$i = $this->ignoreCase ? strripos($this->string, $needle) : strrpos($this->string, $needle); | |
$str->string = false === $i ? '' : substr($str->string, 0, $i + ($includeNeedle ? \strlen($needle) : 0)); | |
} | |
return $str; | |
} | |
public function camel(bool $lcFirst): self | |
{ | |
$str = clone $this; | |
$str->string = str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string))); | |
if ($lcFirst) { | |
$str->string = lcfirst($str->string); | |
} | |
return $str; | |
} | |
public function chunk(int $length = 1): array | |
{ | |
if (1 > $length) { | |
throw new \InvalidArgumentException('The maximum length of each segment must be greater than zero.'); | |
} | |
$chunks = []; | |
if ('' === $this->string) { | |
return []; | |
} | |
foreach (str_split($this->string, $length) as $chunk) { | |
$chunks[] = $str = clone $this; | |
$str->string = $chunk; | |
} | |
return $chunks; | |
} | |
public function endsWith(string $suffix): bool | |
{ | |
if ('' === $suffix) { | |
return true; | |
} | |
return \strlen($this->string) - \strlen($suffix) === ($this->ignoreCase ? strripos($this->string, $suffix) : strrpos($this->string, $suffix)); | |
} | |
public function equalsTo(string $string): bool | |
{ | |
if ($this->ignoreCase) { | |
return 0 === strcasecmp($string, $this->string); | |
} | |
return $string === $this->string; | |
} | |
public function folded(): self | |
{ | |
$str = clone $this; | |
$str->string = strtolower($str->string); | |
return $str; | |
} | |
public function indexOf(string $needle, int $offset = 0): ?int | |
{ | |
if ('' === $needle) { | |
return null; | |
} | |
$i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset); | |
return false === $i ? null : $i; | |
} | |
public function indexOfLast(string $needle, int $offset = 0): ?int | |
{ | |
if ('' === $needle) { | |
return null; | |
} | |
$i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset); | |
return false === $i ? null : $i; | |
} | |
public function join(array $strings): self | |
{ | |
$str = clone $this; | |
$str->string = implode($str->string, $strings); | |
return $str; | |
} | |
public function length(): int | |
{ | |
return \strlen($this->string); | |
} | |
public function lower(): self | |
{ | |
$str = clone $this; | |
$str->string = strtolower($str->string); | |
return $str; | |
} | |
public function match(string $pattern, int $flags = 0, int $offset = 0): ?array | |
{ | |
if ('g' === $pattern[-1]) { | |
$pattern = substr($pattern, 0, -1); | |
$match = 'preg_match_all'; | |
} else { | |
$match = 'preg_match'; | |
} | |
if ($this->ignoreCase) { | |
$pattern .= 'i'; | |
} | |
set_error_handler(static function ($t, $m) { throw new \InvalidArgumentException($m); }); | |
try { | |
if (false === $ret = $match($pattern, $this->string, $matches, $flags, $offset)) { | |
$lastError = preg_last_error(); | |
foreach (get_defined_constants(true)['pcre'] as $k => $v) { | |
if ($lastError === $v && '_ERROR' === substr($k, -6)) { | |
throw new \RuntimeException('Matching failed with '.$k.'.'); | |
} | |
} | |
throw new \RuntimeException('Matching failed with unknown error code.'); | |
} | |
} finally { | |
restore_error_handler(); | |
} | |
return $ret ? $matches : null; | |
} | |
public function padBoth(int $length, string $padStr = ' '): self | |
{ | |
$str = clone $this; | |
$str->string = str_pad($this->string, $length, $padStr, STR_PAD_BOTH); | |
return $str; | |
} | |
public function padEnd(int $length, string $padStr = ' '): self | |
{ | |
$str = clone $this; | |
$str->string = str_pad($this->string, $length, $padStr, STR_PAD_RIGHT); | |
return $str; | |
} | |
public function padStart(int $length, string $padStr = ' '): self | |
{ | |
$str = clone $this; | |
$str->string = str_pad($this->string, $length, $padStr, STR_PAD_LEFT); | |
return $str; | |
} | |
public function prepend(string ...$prefix): self | |
{ | |
$str = clone $this; | |
$str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : implode('', $prefix)).$str->string; | |
return $str; | |
} | |
public function replace(string $from, string $to): self | |
{ | |
$str = clone $this; | |
$str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string); | |
return $str; | |
} | |
public function replaceMatches(string $from, $to): self | |
{ | |
if ('g' === $pattern[-1]) { | |
$pattern = substr($pattern, 0, -1); | |
} | |
if ($this->ignoreCase) { | |
$pattern .= 'i'; | |
} | |
$replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; | |
set_error_handler(static function ($t, $m) { throw new \InvalidArgumentException($m); }); | |
try { | |
if (null === $string = $replace($from, $to, $this->string)) { | |
$lastError = preg_last_error(); | |
foreach (get_defined_constants(true)['pcre'] as $k => $v) { | |
if ($lastError === $v && '_ERROR' === substr($k, -6)) { | |
throw new \RuntimeException('Matching failed with '.$k.'.'); | |
} | |
} | |
throw new \RuntimeException('Matching failed with unknown error code.'); | |
} | |
} finally { | |
restore_error_handler(); | |
} | |
$str = clone $this; | |
$str->string = $string; | |
return $str; | |
} | |
public function slice(int $start = 0, int $length = null): self | |
{ | |
$str = clone $this; | |
$str->string = (string) substr($this->string, $start, $length ?? PHP_INT_MAX); | |
return $str; | |
} | |
public function snake(): self | |
{ | |
$str = $this->toCamelCase(); | |
$str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string)); | |
return $str; | |
} | |
public function splice(string $replacement, int $start = 0, int $length = null): self | |
{ | |
$str = clone $this; | |
$str = substr_replace($this->string, $replacement, $start, $length ?? PHP_INT_MAX); | |
return $str; | |
} | |
public function split(string $delimiter, int $limit = null): array | |
{ | |
if ('' === $delimiter) { | |
return $this->chunk(); | |
} | |
$chunks = $this->ignoreCase | |
? preg_split('{'.preg_quote($delimiter).'}i', $this->string, $limit ?? PHP_INT_MAX) | |
: explode($delimiter, $this->string, $limit ?? PHP_INT_MAX); | |
foreach ($chunks as $i => $chunk) { | |
$chunks[$i] = $str = clone $this; | |
$str->string = $chunk; | |
} | |
return $chunks; | |
} | |
public function startsWith(string $prefix): bool | |
{ | |
if ('' === $prefix) { | |
return true; | |
} | |
return 0 === ($this->ignoreCase ? stripos($this->string, $prefix) : strpos($this->string, $prefix)); | |
} | |
public function title(bool $allWords = false): self | |
{ | |
$str = clone $this; | |
$str->string = $allWords ? ucwords($str->string) : ucfirst($str->string); | |
return $str; | |
} | |
public function trim(string $chars = " \t\n\r\0\x0B\x0C"): self | |
{ | |
$str = clone $this; | |
$str->string = trim($str->string, $chars); | |
return $str; | |
} | |
public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): self | |
{ | |
$str = clone $this; | |
$str->string = rtrim($str->string, $chars); | |
return $str; | |
} | |
public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): self | |
{ | |
$str = clone $this; | |
$str->string = ltrim($str->string, $chars); | |
return $str; | |
} | |
public function upper(): self | |
{ | |
$str = clone $this; | |
$str->string = strtoupper($str->string); | |
return $str; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment