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