xref: /template/strap/ComboStrap/StringUtility.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
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