'I', 'Ö' => 'O', 'Œ' => 'O', 'Ü' => 'U', 'ä' => 'a', 'æ' => 'a', 'ij' => 'i', 'ö' => 'o', 'œ' => 'o', 'ü' => 'u', 'ß' => 's', 'ſ' => 's', 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'A', 'Ā' => 'A', 'Ą' => 'A', 'Ă' => 'A', 'Ç' => 'C', 'Ć' => 'C', 'Č' => 'C', 'Ĉ' => 'C', 'Ċ' => 'C', 'Ď' => 'D', 'Đ' => 'D', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ē' => 'E', 'Ę' => 'E', 'Ě' => 'E', 'Ĕ' => 'E', 'Ė' => 'E', 'Ĝ' => 'G', 'Ğ' => 'G', 'Ġ' => 'G', 'Ģ' => 'G', 'Ĥ' => 'H', 'Ħ' => 'H', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ī' => 'I', 'Ĩ' => 'I', 'Ĭ' => 'I', 'Į' => 'I', 'İ' => 'I', 'Ĵ' => 'J', 'Ķ' => 'K', 'Ľ' => 'K', 'Ĺ' => 'K', 'Ļ' => 'K', 'Ŀ' => 'K', 'Ł' => 'L', 'Ñ' => 'N', 'Ń' => 'N', 'Ň' => 'N', 'Ņ' => 'N', 'Ŋ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ø' => 'O', 'Ō' => 'O', 'Ő' => 'O', 'Ŏ' => 'O', 'Ŕ' => 'R', 'Ř' => 'R', 'Ŗ' => 'R', 'Ś' => 'S', 'Ş' => 'S', 'Ŝ' => 'S', 'Ș' => 'S', 'Š' => 'S', 'Ť' => 'T', 'Ţ' => 'T', 'Ŧ' => 'T', 'Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ū' => 'U', 'Ů' => 'U', 'Ű' => 'U', 'Ŭ' => 'U', 'Ũ' => 'U', 'Ų' => 'U', 'Ŵ' => 'W', 'Ŷ' => 'Y', 'Ÿ' => 'Y', 'Ý' => 'Y', 'Ź' => 'Z', 'Ż' => 'Z', 'Ž' => 'Z', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ā' => 'a', 'ą' => 'a', 'ă' => 'a', 'å' => 'a', 'ç' => 'c', 'ć' => 'c', 'č' => 'c', 'ĉ' => 'c', 'ċ' => 'c', 'ď' => 'd', 'đ' => 'd', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ē' => 'e', 'ę' => 'e', 'ě' => 'e', 'ĕ' => 'e', 'ė' => 'e', 'ƒ' => 'f', 'ĝ' => 'g', 'ğ' => 'g', 'ġ' => 'g', 'ģ' => 'g', 'ĥ' => 'h', 'ħ' => 'h', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ī' => 'i', 'ĩ' => 'i', 'ĭ' => 'i', 'į' => 'i', 'ı' => 'i', 'ĵ' => 'j', 'ķ' => 'k', 'ĸ' => 'k', 'ł' => 'l', 'ľ' => 'l', 'ĺ' => 'l', 'ļ' => 'l', 'ŀ' => 'l', 'ñ' => 'n', 'ń' => 'n', 'ň' => 'n', 'ņ' => 'n', 'ʼn' => 'n', 'ŋ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ø' => 'o', 'ō' => 'o', 'ő' => 'o', 'ŏ' => 'o', 'ŕ' => 'r', 'ř' => 'r', 'ŗ' => 'r', 'ś' => 's', 'š' => 's', 'ť' => 't', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ū' => 'u', 'ů' => 'u', 'ű' => 'u', 'ŭ' => 'u', 'ũ' => 'u', 'ų' => 'u', 'ŵ' => 'w', 'ÿ' => 'y', 'ý' => 'y', 'ŷ' => 'y', 'ż' => 'z', 'ź' => 'z', 'ž' => 'z', 'Α' => 'A', 'Ά' => 'A', 'Ἀ' => 'A', 'Ἁ' => 'A', 'Ἂ' => 'A', 'Ἃ' => 'A', 'Ἄ' => 'A', 'Ἅ' => 'A', 'Ἆ' => 'A', 'Ἇ' => 'A', 'ᾈ' => 'A', 'ᾉ' => 'A', 'ᾊ' => 'A', 'ᾋ' => 'A', 'ᾌ' => 'A', 'ᾍ' => 'A', 'ᾎ' => 'A', 'ᾏ' => 'A', 'Ᾰ' => 'A', 'Ᾱ' => 'A', 'Ὰ' => 'A', 'ᾼ' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', 'Έ' => 'E', 'Ἐ' => 'E', 'Ἑ' => 'E', 'Ἒ' => 'E', 'Ἓ' => 'E', 'Ἔ' => 'E', 'Ἕ' => 'E', 'Ὲ' => 'E', 'Ζ' => 'Z', 'Η' => 'I', 'Ή' => 'I', 'Ἠ' => 'I', 'Ἡ' => 'I', 'Ἢ' => 'I', 'Ἣ' => 'I', 'Ἤ' => 'I', 'Ἥ' => 'I', 'Ἦ' => 'I', 'Ἧ' => 'I', 'ᾘ' => 'I', 'ᾙ' => 'I', 'ᾚ' => 'I', 'ᾛ' => 'I', 'ᾜ' => 'I', 'ᾝ' => 'I', 'ᾞ' => 'I', 'ᾟ' => 'I', 'Ὴ' => 'I', 'ῌ' => 'I', 'Θ' => 'T', 'Ι' => 'I', 'Ί' => 'I', 'Ϊ' => 'I', 'Ἰ' => 'I', 'Ἱ' => 'I', 'Ἲ' => 'I', 'Ἳ' => 'I', 'Ἴ' => 'I', 'Ἵ' => 'I', 'Ἶ' => 'I', 'Ἷ' => 'I', 'Ῐ' => 'I', 'Ῑ' => 'I', 'Ὶ' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => 'K', 'Ο' => 'O', 'Ό' => 'O', 'Ὀ' => 'O', 'Ὁ' => 'O', 'Ὂ' => 'O', 'Ὃ' => 'O', 'Ὄ' => 'O', 'Ὅ' => 'O', 'Ὸ' => 'O', 'Π' => 'P', 'Ρ' => 'R', 'Ῥ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Ύ' => 'Y', 'Ϋ' => 'Y', 'Ὑ' => 'Y', 'Ὓ' => 'Y', 'Ὕ' => 'Y', 'Ὗ' => 'Y', 'Ῠ' => 'Y', 'Ῡ' => 'Y', 'Ὺ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'P', 'Ω' => 'O', 'Ώ' => 'O', 'Ὠ' => 'O', 'Ὡ' => 'O', 'Ὢ' => 'O', 'Ὣ' => 'O', 'Ὤ' => 'O', 'Ὥ' => 'O', 'Ὦ' => 'O', 'Ὧ' => 'O', 'ᾨ' => 'O', 'ᾩ' => 'O', 'ᾪ' => 'O', 'ᾫ' => 'O', 'ᾬ' => 'O', 'ᾭ' => 'O', 'ᾮ' => 'O', 'ᾯ' => 'O', 'Ὼ' => 'O', 'ῼ' => 'O', 'α' => 'a', 'ά' => 'a', 'ἀ' => 'a', 'ἁ' => 'a', 'ἂ' => 'a', 'ἃ' => 'a', 'ἄ' => 'a', 'ἅ' => 'a', 'ἆ' => 'a', 'ἇ' => 'a', 'ᾀ' => 'a', 'ᾁ' => 'a', 'ᾂ' => 'a', 'ᾃ' => 'a', 'ᾄ' => 'a', 'ᾅ' => 'a', 'ᾆ' => 'a', 'ᾇ' => 'a', 'ὰ' => 'a', 'ᾰ' => 'a', 'ᾱ' => 'a', 'ᾲ' => 'a', 'ᾳ' => 'a', 'ᾴ' => 'a', 'ᾶ' => 'a', 'ᾷ' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'έ' => 'e', 'ἐ' => 'e', 'ἑ' => 'e', 'ἒ' => 'e', 'ἓ' => 'e', 'ἔ' => 'e', 'ἕ' => 'e', 'ὲ' => 'e', 'ζ' => 'z', 'η' => 'i', 'ή' => 'i', 'ἠ' => 'i', 'ἡ' => 'i', 'ἢ' => 'i', 'ἣ' => 'i', 'ἤ' => 'i', 'ἥ' => 'i', 'ἦ' => 'i', 'ἧ' => 'i', 'ᾐ' => 'i', 'ᾑ' => 'i', 'ᾒ' => 'i', 'ᾓ' => 'i', 'ᾔ' => 'i', 'ᾕ' => 'i', 'ᾖ' => 'i', 'ᾗ' => 'i', 'ὴ' => 'i', 'ῂ' => 'i', 'ῃ' => 'i', 'ῄ' => 'i', 'ῆ' => 'i', 'ῇ' => 'i', 'θ' => 't', 'ι' => 'i', 'ί' => 'i', 'ϊ' => 'i', 'ΐ' => 'i', 'ἰ' => 'i', 'ἱ' => 'i', 'ἲ' => 'i', 'ἳ' => 'i', 'ἴ' => 'i', 'ἵ' => 'i', 'ἶ' => 'i', 'ἷ' => 'i', 'ὶ' => 'i', 'ῐ' => 'i', 'ῑ' => 'i', 'ῒ' => 'i', 'ῖ' => 'i', 'ῗ' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => 'k', 'ο' => 'o', 'ό' => 'o', 'ὀ' => 'o', 'ὁ' => 'o', 'ὂ' => 'o', 'ὃ' => 'o', 'ὄ' => 'o', 'ὅ' => 'o', 'ὸ' => 'o', 'π' => 'p', 'ρ' => 'r', 'ῤ' => 'r', 'ῥ' => 'r', 'σ' => 's', 'ς' => 's', 'τ' => 't', 'υ' => 'y', 'ύ' => 'y', 'ϋ' => 'y', 'ΰ' => 'y', 'ὐ' => 'y', 'ὑ' => 'y', 'ὒ' => 'y', 'ὓ' => 'y', 'ὔ' => 'y', 'ὕ' => 'y', 'ὖ' => 'y', 'ὗ' => 'y', 'ὺ' => 'y', 'ῠ' => 'y', 'ῡ' => 'y', 'ῢ' => 'y', 'ῦ' => 'y', 'ῧ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'p', 'ω' => 'o', 'ώ' => 'o', 'ὠ' => 'o', 'ὡ' => 'o', 'ὢ' => 'o', 'ὣ' => 'o', 'ὤ' => 'o', 'ὥ' => 'o', 'ὦ' => 'o', 'ὧ' => 'o', 'ᾠ' => 'o', 'ᾡ' => 'o', 'ᾢ' => 'o', 'ᾣ' => 'o', 'ᾤ' => 'o', 'ᾥ' => 'o', 'ᾦ' => 'o', 'ᾧ' => 'o', 'ὼ' => 'o', 'ῲ' => 'o', 'ῳ' => 'o', 'ῴ' => 'o', 'ῶ' => 'o', 'ῷ' => 'o', 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Z', 'З' => 'Z', 'И' => 'I', 'Й' => 'I', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'K', 'Ц' => 'T', 'Ч' => 'C', 'Ш' => 'S', 'Щ' => 'S', 'Ы' => 'Y', 'Э' => 'E', 'Ю' => 'Y', 'Я' => 'Y', 'а' => 'A', 'б' => 'B', 'в' => 'V', 'г' => 'G', 'д' => 'D', 'е' => 'E', 'ё' => 'E', 'ж' => 'Z', 'з' => 'Z', 'и' => 'I', 'й' => 'I', 'к' => 'K', 'л' => 'L', 'м' => 'M', 'н' => 'N', 'о' => 'O', 'п' => 'P', 'р' => 'R', 'с' => 'S', 'т' => 'T', 'у' => 'U', 'ф' => 'F', 'х' => 'K', 'ц' => 'T', 'ч' => 'C', 'ш' => 'S', 'щ' => 'S', 'ы' => 'Y', 'э' => 'E', 'ю' => 'Y', 'я' => 'Y', 'ð' => 'd', 'Ð' => 'D', 'þ' => 't', 'Þ' => 'T', 'ა' => 'a', 'ბ' => 'b', 'გ' => 'g', 'დ' => 'd', 'ე' => 'e', 'ვ' => 'v', 'ზ' => 'z', 'თ' => 't', 'ი' => 'i', 'კ' => 'k', 'ლ' => 'l', 'მ' => 'm', 'ნ' => 'n', 'ო' => 'o', 'პ' => 'p', 'ჟ' => 'z', 'რ' => 'r', 'ს' => 's', 'ტ' => 't', 'უ' => 'u', 'ფ' => 'p', 'ქ' => 'k', 'ღ' => 'g', 'ყ' => 'q', 'შ' => 's', 'ჩ' => 'c', 'ც' => 't', 'ძ' => 'd', 'წ' => 't', 'ჭ' => 'c', 'ხ' => 'k', 'ჯ' => 'j', 'ჰ' => 'h', 'ţ' => 't', 'ʼ' => "'", '̧' => '', 'ḩ' => 'h', '‘' => "'", '’' => "'", 'ừ' => 'u', '/' => '', 'ế' => 'e', 'ả' => 'a', 'ị' => 'i', 'ậ' => 'a', 'ệ' => 'e', 'ỉ' => 'i', 'ồ' => 'o', 'ề' => 'e', 'ơ' => 'o', 'ạ' => 'a', 'ẵ' => 'a', 'ư' => 'u', 'ằ' => 'a', 'ầ' => 'a', 'ḑ' => 'd', 'Ḩ' => 'H', 'Ḑ' => 'D', 'ș' => 's', 'ț' => 't', 'ộ' => 'o', 'ắ' => 'a', 'ş' => 's', "'" => '', 'ու' => 'u', 'ա' => 'a', 'բ' => 'b', 'գ' => 'g', 'դ' => 'd', 'ե' => 'e', 'զ' => 'z', 'է' => 'e', 'ը' => 'y', 'թ' => 't', 'ժ' => 'zh', 'ի' => 'i', 'լ' => 'l', 'խ' => 'kh', 'ծ' => 'ts', 'կ' => 'k', 'հ' => 'h', 'ձ' => 'dz', 'ղ' => 'gh', 'ճ' => 'ch', 'մ' => 'm', 'յ' => 'y', 'ն' => 'n', 'շ' => 'sh', 'ո' => 'o', 'չ' => 'ch', 'պ' => 'p', 'ջ' => 'j', 'ռ' => 'r', 'ս' => 's', 'վ' => 'v', 'տ' => 't', 'ր' => 'r', 'ց' => 'ts', 'փ' => 'p', 'ք' => 'q', 'և' => 'ev', 'օ' => 'o', 'ֆ' => 'f', ]; $arrayFrom = array_keys($transliterationTable); $arrayTo = array_values($transliterationTable); } return str_replace($arrayFrom, $arrayTo, $value); } /** * Transliterate a string to its closest ASCII representation. * * @param string $string * @return string * @see https://github.com/fzaninotto/Faker/blob/master/src/Faker/Provider/Internet.php#L229 */ public static function transliterate($string) { if (0 === preg_match('/[^A-Za-z0-9_.]/', $string)) { return $string; } $transString = static::ascii($string); return preg_replace('/[^A-Za-z0-9_.]/u', '', $transString); } /** * Get the portion of a string before the first occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function before($subject, $search) { if ($search === '') { return $subject; } $result = strstr($subject, (string) $search, true); return $result === false ? $subject : $result; } /** * Get the portion of a string before the last occurrence of a given value. * * @param string $subject * @param string $search * @return string */ public static function beforeLast($subject, $search) { if ($search === '') { return $subject; } $pos = mb_strrpos($subject, $search); if ($pos === false) { return $subject; } return static::substr($subject, 0, $pos); } /** * Get the portion of a string between two given values. * * @param string $subject * @param string $from * @param string $to * @return string */ public static function between($subject, $from, $to) { if ($from === '' || $to === '') { return $subject; } return static::beforeLast(static::after($subject, $from), $to); } /** * Get the smallest possible portion of a string between two given values. * * @param string $subject * @param string $from * @param string $to * @return string */ public static function betweenFirst($subject, $from, $to) { if ($from === '' || $to === '') { return $subject; } return static::before(static::after($subject, $from), $to); } /** * Convert a value to camel case. * * @param string $value * @return string */ public static function camel($value) { if (isset(static::$camelCache[$value])) { return static::$camelCache[$value]; } return static::$camelCache[$value] = lcfirst(static::studly($value)); } /** * Get the character at the specified index. * * @param string $subject * @param int $index * @return string|false */ public static function charAt($subject, $index) { $length = mb_strlen($subject); if ($index < 0 ? $index < -$length : $index > $length - 1) { return false; } return mb_substr($subject, $index, 1); } /** * Remove the given string(s) if it exists at the start of the haystack. * * @param string $subject * @param string|array $needle * @return string */ public static function chopStart($subject, $needle) { foreach ((array) $needle as $n) { if (str_starts_with($subject, $n)) { return substr($subject, strlen($n)); } } return $subject; } /** * Remove the given string(s) if it exists at the end of the haystack. * * @param string $subject * @param string|array $needle * @return string */ public static function chopEnd($subject, $needle) { foreach ((array) $needle as $n) { if (str_ends_with($subject, $n)) { return substr($subject, 0, -strlen($n)); } } return $subject; } /** * Determine if a given string contains a given substring. * * @param string $haystack * @param string|iterable $needles * @param bool $ignoreCase * @return bool */ public static function contains($haystack, $needles, $ignoreCase = false) { if ($ignoreCase) { $haystack = mb_strtolower($haystack); } if (! is_iterable($needles)) { $needles = (array) $needles; } foreach ($needles as $needle) { if ($ignoreCase) { $needle = mb_strtolower($needle); } if ($needle !== '' && str_contains($haystack, $needle)) { return true; } } return false; } /** * Determine if a given string contains all array values. * * @param string $haystack * @param iterable $needles * @param bool $ignoreCase * @return bool */ public static function containsAll($haystack, $needles, $ignoreCase = false) { foreach ($needles as $needle) { if (! static::contains($haystack, $needle, $ignoreCase)) { return false; } } return true; } /** * Replace consecutive instances of a given character * with a single character in the given string. * * @param string $string * @param string $character * @return string */ public static function deduplicate(string $string, string $character = ' ') { return preg_replace( '/'.preg_quote($character, '/').'+/u', $character, $string ); } /** * Determine if a given string ends with a given substring. * * @param string $haystack * @param array|string $needles * @return bool */ public static function endsWith($haystack, $needles) { if (! is_iterable($needles)) { $needles = (array) $needles; } if (is_null($haystack)) { return false; } foreach ($needles as $needle) { if ((string) $needle !== '' && str_ends_with($haystack, $needle)) { return true; } } return false; } /** * Cap a string with a single instance of a given value. * * @param string $value * @param string $cap * @return string */ public static function finish($value, $cap) { $quoted = preg_quote($cap, '/'); return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap; } /** * Determine if a given string matches a given pattern. * * @param string|array $pattern * @param string $value * @return bool */ public static function is($pattern, $value) { $patterns = Arr::wrap($pattern); $value = (string) $value; if (empty($patterns)) { return false; } foreach ($patterns as $pattern) { $pattern = (string) $pattern; // If the given value is an exact match we can of course return // true right from the beginning. Otherwise, we will translate // asterisks and do an actual pattern match against the // two strings to see if they match. if ($pattern == $value) { return true; } $pattern = preg_quote($pattern, '#'); // Asterisks are translated into zero-or-more regular expression // wildcards to make it convenient to check if the strings // starts with the given pattern such as "library/*", // making any string check convenient. $pattern = str_replace('\*', '.*', $pattern); if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { return true; } } return false; } /** * Converts a non-boolean value to boolean * @param string|int $str * @return bool|null */ public static function toBool($str) { if (is_bool($str)) { return $str; } $truthy = ['yes', 'on', 'true', '1', 1]; $falsy = ['no', 'off', 'false', '0', 0, '']; if (in_array($str, $truthy, true)) { return true; } elseif (in_array($str, $falsy, true)) { return false; } } /** * Determine if a given string is 7 bit ASCII. * * @param string $value * @return bool * @see https://developer.wordpress.org/reference/classes/requests_idnaencoder/is_ascii/ */ public static function isAscii($value) { return (preg_match('/(?:[^\x00-\x7F])/', $value) !== 1); } /** * Checks if the word(s) are in capitalized form. * @param string $str * @param boolean $onlyFirst if true, checks only the first charatcer * @return boolean */ public static function isCapitalized($str, $onlyFirst = false) { if ($onlyFirst) { return static::isUpper($str[0]); } if ($words = mb_split('\s', $str)) { foreach ($words as $word) { $isCap[] = static::isUpper($word[0]) && static::isLower(mb_substr($word, 1)); } return count(array_filter($isCap)) === count($isCap); } } /** * Checks if the first character is in capital form. * * @param string $str * @return boolean */ public static function isCapital($str) { return static::isCapitalized($str, true); } /** * Checks if the chracters are in upper case * * @param string $str * @return boolean */ public static function isUpper($str) { return $str === static::upper($str); } /** * Checks if the chracters are in lower case * * @param string $str * @return boolean */ public static function isLower($str) { return $str === static::lower($str); } /** * Checks if two words sounds alike * * @param string $str1 * @param string $str2 * @return bool */ public static function soundsAlike($str1, $str2) { return soundex($str1) == soundex($str2); } /** * Checks if two words are similar * * @param string $str1 * @param string $str2 * * @return bool */ public static function isSimilar($str1, $str2, $accuracy = 60) { $percent = static::similarityOf($str1, $str2); return $percent > $accuracy; } /** * Checks if two words are similar * * @param string $str1 * @param string $str2 * * @return bool */ public static function similarityOf($str1, $str2) { similar_text($str1, $str2, $percent); return $percent; } /** * Determine if a given value is valid JSON. * * @param mixed $value * @return bool */ public static function isJson($value) { if (! is_string($value)) { return false; } try { json_decode($value, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { return false; } return true; } /** * Determine if a given value is a valid URL. * * @param mixed $value * @param array $protocols * @return bool */ public static function isUrl($value, array $protocols = []) { if (! is_string($value)) { return false; } $protocolList = empty($protocols) ? 'aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|tg|things|thismessage|tip|tn3270|tool|ts3server|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s' : implode('|', $protocols); /* * This pattern is derived from Symfony\Component\Validator\Constraints\UrlValidator (5.0.7). * * (c) Fabien Potencier http://symfony.com */ $pattern = '~^ (FLUENT_PROTOCOLS):// # protocol (((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+)@)? # basic auth ( ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or \[ (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::)))) \] # an IPv6 address ) (:[0-9]+)? # a port (optional) (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})* )* # a path (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a query (optional) (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%[0-9A-Fa-f]{2})* )? # a fragment (optional) $~ixu'; return preg_match(str_replace('FLUENT_PROTOCOLS', $protocolList, $pattern), $value) > 0; } /** * Determine if a given string is a valid UUID. * * @param string $value * @return bool */ public static function isUuid($value) { return wp_is_uuid($value); } /** * Convert a string to kebab case. * * @param string $value * @return string */ public static function kebab($value) { return static::snake($value, '-'); } /** * Return the length of the given string. * * @param string $value * @param string|null $encoding * @return int */ public static function length($value, $encoding = null) { if ($encoding) { return mb_strlen($value, $encoding); } return mb_strlen($value); } /** * Limit the number of characters in a string. * * @param string $value * @param int $limit * @param string $end * @param bool $preserveWords * @return string */ public static function limit( $value, $limit = 100, $end = '...', $preserveWords = false ) { if (mb_strwidth($value, 'UTF-8') <= $limit) { return $value; } if (! $preserveWords) { return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end; } $value = trim(preg_replace('/[\n\r]+/', ' ', strip_tags($value))); $trimmed = rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')); if (mb_substr($value, $limit, 1, 'UTF-8') === ' ') { return $trimmed.$end; } return preg_replace("/(.*)\s.*/", '$1', $trimmed).$end; } /** * Convert the given string to lower-case. * * @param string $value * @return string */ public static function lower($value) { return mb_strtolower($value, 'UTF-8'); } /** * Limit the number of words in a string. * * @param string $value * @param int $words * @param string $end * @return string */ public static function words($value, $words = 100, $end = '...') { preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches); if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) { return $value; } return rtrim($matches[0]).$end; } /** * Masks a portion of a string with a repeated character. * * @param string $string * @param string $character * @param int $index * @param int|null $length * @param string $encoding * @return string */ public static function mask( $string, $character, $index, $length = null, $encoding = 'UTF-8' ) { if ($character === '') { return $string; } if (is_null($length) && PHP_MAJOR_VERSION < 8) { $length = mb_strlen($string, $encoding); } $segment = mb_substr($string, $index, $length, $encoding); if ($segment === '') { return $string; } $strlen = mb_strlen($string, $encoding); $startIndex = $index; if ($index < 0) { $startIndex = $index < -$strlen ? 0 : $strlen + $index; } $start = mb_substr($string, 0, $startIndex, $encoding); $segmentLen = mb_strlen($segment, $encoding); $end = mb_substr($string, $startIndex + $segmentLen); return $start.str_repeat(mb_substr($character, 0, 1, $encoding), $segmentLen).$end; } /** * Get the string matching the given pattern. * * @param string $pattern * @param string $subject * @return string */ public static function match($pattern, $subject) { preg_match($pattern, $subject, $matches); if (! $matches) { return ''; } return $matches[1] ?? $matches[0]; } /** * Determine if a given string matches a given pattern. * * @param string|iterable $pattern * @param string $value * @return bool */ public static function isMatch($pattern, $value) { $value = (string) $value; if (! is_iterable($pattern)) { $pattern = [$pattern]; } foreach ($pattern as $pattern) { $pattern = (string) $pattern; if (preg_match($pattern, $value) === 1) { return true; } } return false; } /** * Get the string matching the given pattern. * * @param string $pattern * @param string $subject * @return \FluentBoards\Framework\Support\Collection */ public static function matchAll($pattern, $subject) { preg_match_all($pattern, $subject, $matches); if (empty($matches[0])) { return Helper::collect(); } return Helper::collect($matches[1] ?? $matches[0]); } /** * Pad both sides of a string with another. * * @param string $value * @param int $length * @param string $pad * @return string */ public static function padBoth($value, $length, $pad = ' ') { return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_BOTH); } /** * Pad the left side of a string with another. * * @param string $value * @param int $length * @param string $pad * @return string */ public static function padLeft($value, $length, $pad = ' ') { return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_LEFT); } /** * Pad the right side of a string with another. * * @param string $value * @param int $length * @param string $pad * @return string */ public static function padRight($value, $length, $pad = ' ') { return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_RIGHT); } /** * Parse a Class[@]method style callback into class and method. * * @param string $callback * @param string|null $default * @return array */ public static function parseCallback($callback, $default = null) { return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default]; } /** * Parse an integer from a string. * * @param string $value * @return int|null */ public static function parseInt($value) { if (preg_match('/[-+]?\d+/', $value, $matches)) { return (int) $matches[0]; } } /** * Parse a floasting point number from a string. * * @param string $value * @return float|null */ public static function parseFloat($value) { if (preg_match('/[-+]?\d*\.?\d+(e[-+]?\d+)?/i', $value, $matches)) { return (float) $matches[0]; } } /** * Remove all non-numeric characters from a string. * * @param string $value * @return string */ public static function parseNumber($value) { return preg_replace('/[^0-9]/', '', $value); } /** * Get the plural form of an English word. * * @param string $value * @param int|array|\Countable $count * @return string */ public static function plural($value, $count = 2) { return Pluralizer::plural($value, $count); } /** * Pluralize the last word of an English, studly caps case string. * * @param string $value * @param int|array|\Countable $count * @return string */ public static function pluralStudly($value, $count = 2) { $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); $lastWord = array_pop($parts); return implode('', $parts).self::plural($lastWord, $count); } /** * Find the multi-byte safe position of the first * occurrence of a given substring in a string. * * @param string $haystack * @param string $needle * @param int $offset * @param string|null $encoding * @return int|false */ public static function position( $haystack, $needle, $offset = 0, $encoding = null ) { return mb_strpos($haystack, (string) $needle, $offset, $encoding); } /** * Generate a more truly "random" alpha-numeric string. * * @param int $length * @return string */ public static function random($length = 16) { $string = ''; while (($len = strlen($string)) < $length) { $size = $length - $len; $bytes = random_bytes($size); $string .= substr( str_replace( ['/', '+', '='], '', base64_encode($bytes) ), 0, $size ); } return $string; } /** * Repeat the given string. * * @param string $string * @param int $times * @return string */ public static function repeat(string $string, int $times) { return str_repeat($string, $times); } /** * Replace a given value in the string sequentially with an array. * * @param string $search * @param array $replace * @param string $subject * @return string */ public static function replaceArray($search, array $replace, $subject) { $segments = explode($search, $subject); $result = array_shift($segments); foreach ($segments as $segment) { $result .= (array_shift($replace) ?? $search).$segment; } return $result; } /** * Replace the given value in the given string. * * @param string|iterable $search * @param string|iterable $replace * @param string|iterable $subject * @param bool $caseSensitive * @return string|string[] */ public static function replace($search, $replace, $subject, $caseSensitive = true) { if ($search instanceof Traversable) { $search = (new Collection($search))->all(); } if ($replace instanceof Traversable) { $replace = (new Collection($replace))->all(); } if ($subject instanceof Traversable) { $subject = (new Collection($subject))->all(); } return $caseSensitive ? str_replace($search, $replace, $subject) : str_ireplace($search, $replace, $subject); } /** * Replace the first occurrence of a given value in the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceFirst($search, $replace, $subject) { if ($search === '') { return $subject; } $position = strpos($subject, $search); if ($position !== false) { return substr_replace($subject, $replace, $position, strlen($search)); } return $subject; } /** * Replace the first occurrence of the given value if it appears at the start of the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceStart($search, $replace, $subject) { $search = (string) $search; if ($search === '') { return $subject; } if (static::startsWith($subject, $search)) { return static::replaceFirst($search, $replace, $subject); } return $subject; } /** * Replace the last occurrence of a given value in the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceLast($search, $replace, $subject) { if ($search === '') { return $subject; } $position = strrpos($subject, $search); if ($position !== false) { return substr_replace($subject, $replace, $position, strlen($search)); } return $subject; } /** * Replace the last occurrence of a given value if it appears at the end of the string. * * @param string $search * @param string $replace * @param string $subject * @return string */ public static function replaceEnd($search, $replace, $subject) { $search = (string) $search; if ($search === '') { return $subject; } if (static::endsWith($subject, $search)) { return static::replaceLast($search, $replace, $subject); } return $subject; } /** * Replace the patterns matching the given regular expression. * * @param array|string $pattern * @param \Closure|string[]|string $replace * @param array|string $subject * @param int $limit * @return string|string[]|null */ public static function replaceMatches($pattern, $replace, $subject, $limit = -1) { if ($replace instanceof \Closure) { return preg_replace_callback($pattern, $replace, $subject, $limit); } return preg_replace($pattern, $replace, $subject, $limit); } /** * Remove any occurrence of the given string in the subject. * * @param string|array $search * @param string $subject * @param bool $caseSensitive * @return string */ public static function remove($search, $subject, $caseSensitive = true) { $subject = $caseSensitive ? str_replace($search, '', $subject) : str_ireplace($search, '', $subject); return $subject; } /** * Reverse the given string. * * @param string $value * @return string */ public static function reverse(string $value) { return implode(array_reverse(mb_str_split($value))); } /** * Begin a string with a single instance of a given value. * * @param string $value * @param string $prefix * @return string */ public static function start($value, $prefix) { $quoted = preg_quote($prefix, '/'); return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value); } /** * Convert the given string to upper-case. * * @param string $value * @return string */ public static function upper($value) { return mb_strtoupper($value, 'UTF-8'); } /** * Convert the given string to title case. * * @param string $value * @return string */ public static function title($value) { return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); } /** * Convert the given string to title case for each word. * * @param string $value * @return string */ public static function headline($value) { $parts = explode(' ', $value); $parts = count($parts) > 1 ? $parts = array_map([static::class, 'title'], $parts) : $parts = array_map([static::class, 'title'], static::ucsplit(implode('_', $parts))); $collapsed = static::replace(['-', '_', ' '], '_', implode('_', $parts)); return implode(' ', array_filter(explode('_', $collapsed))); } /** * Convert the given string to APA-style title case. * * See: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case * * @param string $value * @return string */ public static function apa($value) { if (trim($value) === '') { return $value; } $minorWords = [ 'and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet', 'a', 'an', 'the', 'at', 'by', 'for', 'in', 'of', 'off', 'on', 'per', 'to', 'up', 'via', 'et', 'ou', 'un', 'une', 'la', 'le', 'les', 'de', 'du', 'des', 'par', 'à', ]; $endPunctuation = ['.', '!', '?', ':', '—', ',']; $words = preg_split('/\s+/', $value, -1, PREG_SPLIT_NO_EMPTY); for ($i = 0; $i < count($words); $i++) { $lowercaseWord = mb_strtolower($words[$i]); if (str_contains($lowercaseWord, '-')) { $hyphenatedWords = explode('-', $lowercaseWord); $hyphenatedWords = array_map(function ($part) use ($minorWords) { return (in_array($part, $minorWords) && mb_strlen($part) <= 3) ? $part : mb_strtoupper(mb_substr($part, 0, 1)).mb_substr($part, 1); }, $hyphenatedWords); $words[$i] = implode('-', $hyphenatedWords); } else { if (in_array($lowercaseWord, $minorWords) && mb_strlen($lowercaseWord) <= 3 && ! ($i === 0 || in_array(mb_substr($words[$i - 1], -1), $endPunctuation))) { $words[$i] = $lowercaseWord; } else { $words[$i] = mb_strtoupper(mb_substr($lowercaseWord, 0, 1)).mb_substr($lowercaseWord, 1); } } } return implode(' ', $words); } /** * Get the singular form of an English word. * * @param string $value * @return string */ public static function singular($value) { return Pluralizer::singular($value); } /** * Generate a URL friendly "slug" from a given string. * * @param string $title * @return string * @see https://developer.wordpress.org/reference/functions/sanitize_title/ */ public static function slug($title, $fallback_title = '', $context = 'save') { return sanitize_title($title, $fallback_title, $context); } /** * Convert a string to snake case. * * @param string $value * @param string $delimiter * @return string */ public static function snake($value, $delimiter = '_') { $key = $value; if (isset(static::$snakeCache[$key][$delimiter])) { return static::$snakeCache[$key][$delimiter]; } if (! ctype_lower($value)) { $value = preg_replace('/\s+/u', '', ucwords($value)); $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); } return static::$snakeCache[$key][$delimiter] = $value; } /** * Remove whitespace (including special Unicode spaces) from a string. * * Supports trimming from left, right, or both ends, and allows * specifying additional characters to trim. * * @param string $value The string to trim. * @param string|null $charlist Optional additional characters to trim. * @param string $mode One of 'both' (default), 'left', 'right'. * * @return string The trimmed string. */ protected static function _unicodeTrim(string $value, ?string $charlist = null, string $mode = 'both'): string { $defaultChars = " \n\r\t\v"; // \0 omitted to avoid null byte errors $chars = $charlist ?? $defaultChars; $quoted = preg_quote($chars, '~'); // Unicode invisible spaces we want to include $unicodeSpaces = '\s\x{FEFF}\x{200B}\x{200E}'; switch ($mode) { case 'left': $pattern = '~^[' . $unicodeSpaces . $quoted . ']+~u'; break; case 'right': $pattern = '~[' . $unicodeSpaces . $quoted . ']+$~u'; break; case 'both': default: $pattern = '~^[' . $unicodeSpaces . $quoted . ']+|[' . $unicodeSpaces . $quoted . ']+$~u'; break; } return preg_replace($pattern, '', $value) ?? $value; } /** * Remove all whitespace (including special Unicode spaces) from both ends of a string. * * @param string $value The string to trim. * @param string|null $charlist Optional additional characters to trim. * * @return string The trimmed string. */ public static function trim(string $value, ?string $charlist = null): string { return static::_unicodeTrim($value, $charlist, 'both'); } /** * Remove all whitespace (including special Unicode spaces) from the beginning of a string. * * @param string $value The string to trim. * @param string|null $charlist Optional additional characters to trim. * * @return string The trimmed string. */ public static function ltrim(string $value, ?string $charlist = null): string { return static::_unicodeTrim($value, $charlist, 'left'); } /** * Remove all whitespace (including special Unicode spaces) from the end of a string. * * @param string $value The string to trim. * @param string|null $charlist Optional additional characters to trim. * * @return string The trimmed string. */ public static function rtrim(string $value, ?string $charlist = null): string { return static::_unicodeTrim($value, $charlist, 'right'); } /** * Remove all "extra" blank space from the given string. * * @param string $value * @return string */ public static function squish($value) { return preg_replace('~(\s|\x{3164}|\x{1160})+~u', ' ', preg_replace('~^[\s\x{FEFF}]+|[\s\x{FEFF}]+$~u', '', $value)); } /** * Determine if a given string starts with a given substring. * * @param string $haystack * @param string|iterable $needles * @return bool */ public static function startsWith($haystack, $needles) { if (!is_iterable($needles)) { $needles = [$needles]; } if ($haystack === null) { return false; } foreach ($needles as $needle) { if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) { return true; } } return false; } /** * Convert a value to studly caps case. * * @param string $value * @return string */ public static function studly($value) { $key = $value; if (isset(static::$studlyCache[$key])) { return static::$studlyCache[$key]; } $words = explode(' ', static::replace(['-', '_'], ' ', $value)); $studlyWords = array_map(function ($word) { return static::ucfirst($word); }, $words); return static::$studlyCache[$key] = implode($studlyWords); } /** * Convert a value to Pascal case. * * @param string $value * @return string */ public static function pascal($value) { return static::studly($value); } /** * Returns the portion of the string specified by the start and length parameters. * * @param string $string * @param int $start * @param int|null $length * @return string */ public static function substr($string, $start, $length = null) { return mb_substr($string, $start, $length, 'UTF-8'); } /** * Returns the number of substring occurrences. * * @param string $haystack * @param string $needle * @param int $offset * @param int|null $length * @return int */ public static function substrCount( $haystack, $needle, $offset = 0, $length = null ) { if (! is_null($length)) { return substr_count($haystack, $needle, $offset, $length); } else { return substr_count($haystack, $needle, $offset); } } /** * Replace text within a portion of a string. * * @param string|array $string * @param string|array $replace * @param array|int $offset * @param array|int|null $length * @return string|array */ public static function substrReplace( $string, $replace, $offset = 0, $length = null ) { if ($length === null) { $length = strlen($string); } return substr_replace($string, $replace, $offset, $length); } /** * Swap multiple keywords in a string with other keywords. * * @param array $map * @param string $subject * @return string */ public static function swap(array $map, $subject) { return strtr($subject, $map); } /** * Take the first or last {$limit} characters of a string. * * @param string $string * @param int $limit * @return string */ public static function take($string, int $limit): string { if ($limit < 0) { return static::substr($string, $limit); } return static::substr($string, 0, $limit); } /** * Convert the given string to Base64 encoding. * * @param string $string * @return string */ public static function toBase64($string) { return base64_encode($string); } /** * Decode the given Base64 encoded string. * * @param string $string * @param bool $strict * @return string|false */ public static function fromBase64($string, $strict = false) { return base64_decode($string, $strict); } /** * Make a string's first character lowercase. * * @param string $string * @return string */ public static function lcfirst($string) { return static::lower( static::substr($string, 0, 1) ).static::substr($string, 1); } /** * Make a string's first character uppercase. * * @param string $string * @return string */ public static function ucfirst($string) { return static::upper( static::substr($string, 0, 1) ).static::substr($string, 1); } /** * Split a string into pieces by uppercase characters. * * @param string $string * @return array */ public static function ucsplit($string) { return preg_split('/(?=\p{Lu})/u', $string, -1, PREG_SPLIT_NO_EMPTY); } /** * Count the number of words in a UTF-8 string. * * @param string $string * @return int */ public static function wordCount(string $string) { $words = preg_split('/[^\p{L}\p{N}]+/u', $string, -1, PREG_SPLIT_NO_EMPTY); return count($words); } /** * Wrap a string to a given number of characters. * * @param string $string * @param int $characters * @param string $break * @param bool $cutLongWords * @return string */ public static function wordWrap( $string, $characters = 75, $break = "\n", $cutLongWords = false ) { return wordwrap($string, $characters, $break, $cutLongWords); } /** * Wrap the string with the given strings. * * @param string $value * @param string $before * @param string|null $after * @return string */ public static function wrap($value, $before, $after = null) { return $before.$value.($after = $after ?: $before); } /** * Generate a UUID (version 4). * * @return string */ public static function uuid() { return wp_generate_uuid4(); } /** * Increment a counter. * @return int */ public static function incrementCounter($prefix = '') { return wp_unique_id($prefix); } /** * Generate a deterministic unique id by a prefix. * * @param string $slug * @return string */ public static function incrementBySlug($slug = '') { return wp_unique_prefixed_id( $slug = $slug ?: App::config()->get('app.slug') ); } /** * Remove all strings from the casing caches. * * @return void */ public static function flushCache() { static::$snakeCache = []; static::$camelCache = []; static::$studlyCache = []; } }