1<?php 2 3namespace ComboStrap; 4 5use ComboStrap\Web\Url; 6 7/** 8 * Class StringUtility 9 * @package ComboStrap 10 * A class with string utility 11 */ 12class StringUtility 13{ 14 15 public const SEPARATORS_CHARACTERS = [".", "(", ")", ",", "-"]; 16 17 18 /** 19 * Generate a text with a max length of $length 20 * and add ... if above 21 * @param $myString 22 * @param $length 23 * @return string 24 */ 25 static function truncateString($myString, $length): string 26 { 27 28 if (strlen($myString) > $length) { 29 $suffix = ' ...'; 30 $myString = substr($myString, 0, ($length - 1) - strlen($suffix)) . $suffix; 31 } 32 return $myString; 33 } 34 35 /** 36 * @param $string 37 * @return string - the string without any carriage return 38 * Used to compare string without worrying about carriage return 39 */ 40 public static function normalized($string) 41 { 42 return str_replace("\n", "", $string); 43 } 44 45 /** 46 * @param $needle 47 * @param $haystack 48 * @return bool 49 */ 50 public static function contain($needle, $haystack) 51 { 52 $pos = strpos($haystack, $needle); 53 if ($pos === FALSE) { 54 return false; 55 } else { 56 return true; 57 } 58 } 59 60 public static function toString($value) 61 { 62 /** 63 * No transformation if it's a string 64 * var_export below is not idempotent 65 * ie \ would become \\ 66 */ 67 if (is_string($value)) { 68 return $value; 69 } 70 71 if (is_array($value)) { 72 $string = var_export($value, true); 73 74 // An array value gets command in var_export 75 $lastCharacterIndex = strlen($string) - 1; 76 if ($string[0] === "'" && $string[$lastCharacterIndex] === "'") { 77 $string = substr($string, 1, strlen($string) - 2); 78 } 79 return $string; 80 } 81 82 if (is_object($value)) { 83 if (method_exists($value, "__toString")) { 84 return strval($value); 85 } else { 86 return get_class($value); 87 } 88 } 89 90 if (is_numeric($value)) { 91 return strval($value); 92 } 93 94 if (is_bool($value)) { 95 return var_export($value, true); 96 } 97 98 $string = var_export($value, true); 99 LogUtility::msg("The type of the value ($string) is unknown and could not be properly cast to string", LogUtility::LVL_MSG_WARNING); 100 return $string; 101 102 } 103 104 /** 105 * Add an EOL if not present at the end of the string 106 * @param $doc 107 */ 108 public static function addEolCharacterIfNotPresent(&$doc) 109 { 110 $strlen = strlen($doc); 111 if ($strlen < 1) { 112 return; 113 } 114 if ($doc[$strlen - 1] != DOKU_LF) { 115 $doc .= DOKU_LF; 116 } 117 } 118 119 /** 120 * Delete the string from the end 121 * This is used generally to delete the previous opening tag of an header or a blockquote 122 * @param $doc 123 * @param $string 124 */ 125 public static function rtrim(&$doc, $string) 126 { 127 128 /** 129 * We trim because in the process, we may get extra {@link DOKU_LF} at the end 130 */ 131 $doc = trim($doc); 132 $string = trim($string); 133 $length = strlen($doc) - strlen($string); 134 if (substr($doc, $length) === $string) { 135 $doc = substr($doc, 0, $length); 136 } 137 138 } 139 140 /** 141 * Delete the string from the beginning 142 * This is used to delete a tag for instance 143 * @param $doc 144 * @param $string 145 */ 146 public static function ltrim(&$doc, $string) 147 { 148 149 $doc = trim($doc); 150 $string = trim($string); 151 $length = strlen($string); 152 if (substr($doc, 0, $length) === $string) { 153 $doc = substr($doc, $length); 154 } 155 156 } 157 158 /** 159 * The word count does not take into account 160 * words with non-words characters such as < = 161 * Therefore the node <node> and attribute name=value are not taken in the count 162 * @param $text 163 * @return int the number of words 164 */ 165 public static function getWordCount($text) 166 { 167 /** 168 * Delete the frontmatter 169 */ 170 $text = preg_replace("/^---(json)?$.*^---$/Ums", "", $text); 171 /** 172 * New line for node 173 */ 174 $text = str_replace("<", "\n<", $text); 175 $text = str_replace(">", ">\n", $text); 176 // \s shorthand for whitespace 177 // | the table and links are separated with a | 178 // / to take into account expression such as and/or 179 // /u for unicode support (https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php) 180 $wordSeparator = '/[\s|\/]/u'; 181 $preg_split = preg_split($wordSeparator, $text); 182 $wordsWithoutEmpty = array_filter($preg_split, self::class . '::isWord'); 183 return count($wordsWithoutEmpty); 184 } 185 186 public static function normalize($expected) 187 { 188 $expected = preg_replace("/[\s]/", " ", $expected); 189 $expected = str_replace(" ", " ", $expected); 190 $expected = str_replace(" ", " ", $expected); 191 $expected = str_replace(" ", " ", $expected); 192 $expected = str_replace(" ", " ", $expected); 193 return trim($expected); 194 195 } 196 197 /** 198 * @param $text 199 * @return bool 200 */ 201 public static function isWord($text) 202 { 203 if (empty($text)) { 204 return false; 205 } 206 /** 207 * We also allow `-` minus 208 * 209 * And because otherwise the words are not counted: 210 * * `'` (used to highlight words) 211 * * `[]` used in links 212 * * `,` used at the end of a sentenct 213 */ 214 $preg_match = preg_match("/^[\w\-'\]\[,]*$/u", $text); 215 return $preg_match == 1; 216 } 217 218 public static function match($subject, $pattern) 219 { 220 return preg_match("/$pattern/", $subject) === 1; 221 } 222 223 public static function endWiths($string, $suffix) 224 { 225 $suffixStartPosition = strlen($string) - strlen($suffix); 226 return strrpos($string, $suffix) === $suffixStartPosition; 227 } 228 229 public static function explodeAndTrim($string, $delimiter = ",") 230 { 231 return array_map('trim', explode($delimiter, $string)); 232 } 233 234 public static function lastIndexOf($haystack, $needle) 235 { 236 /** 237 * strRpos 238 * and not strpos 239 */ 240 return strrpos($haystack, $needle); 241 } 242 243 public static function startWiths($string, $prefix) 244 { 245 return strrpos($string, $prefix) === 0; 246 } 247 248 /** 249 * @param $string 250 * @param null $separatorsCharacters - characters that will separate the words 251 * @return array a words 252 */ 253 public static function getWords($string, $separatorsCharacters = null): array 254 { 255 // Reserved characters to space 256 if ($separatorsCharacters === null) { 257 $separatorsCharacters = StringUtility::getAllSeparators(); 258 } 259 if (!is_array($separatorsCharacters)) { 260 LogUtility::msg("The separators characters are not an array, default characters used"); 261 $separatorsCharacters = StringUtility::getAllSeparators(); 262 } 263 264 $string = str_replace($separatorsCharacters, " ", $string); 265 // Doubles spaces to space 266 $string = preg_replace("/\s{2,}/", " ", $string); 267 // Trim space 268 $string = trim($string); 269 270 return explode(" ", $string); 271 } 272 273 private static function getAllSeparators(): array 274 { 275 return array_merge( 276 Url::RESERVED_WORDS, 277 LocalPath::RESERVED_WINDOWS_CHARACTERS, 278 StringUtility::SEPARATORS_CHARACTERS 279 ); 280 } 281 282} 283