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 if ($doc[strlen($doc) - 1] != DOKU_LF) { 111 $doc .= DOKU_LF; 112 } 113 } 114 115 /** 116 * Delete the string from the end 117 * This is used generally to delete the previous opening tag of an header or a blockquote 118 * @param $doc 119 * @param $string 120 */ 121 public static function rtrim(&$doc, $string) 122 { 123 124 /** 125 * We trim because in the process, we may get extra {@link DOKU_LF} at the end 126 */ 127 $doc = trim($doc); 128 $string = trim($string); 129 $length = strlen($doc) - strlen($string); 130 if (substr($doc, $length) === $string) { 131 $doc = substr($doc, 0, $length); 132 } 133 134 } 135 136 /** 137 * Delete the string from the beginning 138 * This is used to delete a tag for instance 139 * @param $doc 140 * @param $string 141 */ 142 public static function ltrim(&$doc, $string) 143 { 144 145 $doc = trim($doc); 146 $string = trim($string); 147 $length = strlen($string); 148 if (substr($doc, 0, $length) === $string) { 149 $doc = substr($doc, $length); 150 } 151 152 } 153 154 /** 155 * The word count does not take into account 156 * words with non-words characters such as < = 157 * Therefore the node <node> and attribute name=value are not taken in the count 158 * @param $text 159 * @return int the number of words 160 */ 161 public static function getWordCount($text) 162 { 163 /** 164 * Delete the frontmatter 165 */ 166 $text = preg_replace("/^---(json)?$.*^---$/Ums", "", $text); 167 /** 168 * New line for node 169 */ 170 $text = str_replace("<", "\n<", $text); 171 $text = str_replace(">", ">\n", $text); 172 // \s shorthand for whitespace 173 // | the table and links are separated with a | 174 // / to take into account expression such as and/or 175 // /u for unicode support (https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php) 176 $wordSeparator = '/[\s|\/]/u'; 177 $preg_split = preg_split($wordSeparator, $text); 178 $wordsWithoutEmpty = array_filter($preg_split, 'self::isWord'); 179 return count($wordsWithoutEmpty); 180 } 181 182 public static function normalize($expected) 183 { 184 $expected = preg_replace("/[\s]/", " ", $expected); 185 $expected = str_replace(" ", " ", $expected); 186 $expected = str_replace(" ", " ", $expected); 187 $expected = str_replace(" ", " ", $expected); 188 $expected = str_replace(" ", " ", $expected); 189 return trim($expected); 190 191 } 192 193 /** 194 * @param $text 195 * @return bool 196 */ 197 public static function isWord($text) 198 { 199 if (empty($text)) { 200 return false; 201 } 202 /** 203 * We also allow `-` minus 204 * 205 * And because otherwise the words are not counted: 206 * * `'` (used to highlight words) 207 * * `[]` used in links 208 * * `,` used at the end of a sentenct 209 */ 210 $preg_match = preg_match("/^[\w\-'\]\[,]*$/u", $text); 211 return $preg_match == 1; 212 } 213 214 public static function match($subject, $pattern) 215 { 216 return preg_match("/$pattern/", $subject) === 1; 217 } 218 219 public static function endWiths($string, $suffix) 220 { 221 $suffixStartPosition = strlen($string) - strlen($suffix); 222 return strrpos($string, $suffix) === $suffixStartPosition; 223 } 224 225 public static function explodeAndTrim($string, $delimiter = ",") 226 { 227 return array_map('trim', explode($delimiter, $string)); 228 } 229 230 public static function lastIndexOf($haystack, $needle) 231 { 232 /** 233 * strRpos 234 * and not strpos 235 */ 236 return strrpos($haystack, $needle); 237 } 238 239 public static function startWiths($string, $prefix) 240 { 241 return strrpos($string, $prefix) === 0; 242 } 243 244 /** 245 * @param $string 246 * @param null $separatorsCharacters - characters that will separate the words 247 * @return array a words 248 */ 249 public static function getWords($string, $separatorsCharacters = null): array 250 { 251 // Reserved characters to space 252 if ($separatorsCharacters === null) { 253 $separatorsCharacters = StringUtility::getAllSeparators(); 254 } 255 if (!is_array($separatorsCharacters)) { 256 LogUtility::msg("The separators characters are not an array, default characters used"); 257 $separatorsCharacters = StringUtility::getAllSeparators(); 258 } 259 260 $string = str_replace($separatorsCharacters, " ", $string); 261 // Doubles spaces to space 262 $string = preg_replace("/\s{2,}/", " ", $string); 263 // Trim space 264 $string = trim($string); 265 266 return explode(" ", $string); 267 } 268 269 private static function getAllSeparators(): array 270 { 271 return array_merge( 272 Url::RESERVED_WORDS, 273 LocalPath::RESERVED_WINDOWS_CHARACTERS, 274 StringUtility::SEPARATORS_CHARACTERS 275 ); 276 } 277 278} 279