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