PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.8
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Calculation / TextData.php

TextData.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.4.8, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData.php

673 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5 use PhpOffice\PhpSpreadsheet\Shared\Date;
6 use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
7 use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
8
9 class TextData
10 {
11 private static $invalidChars;
12
13 private static function unicodeToOrd($character)
14 {
15 return unpack('V', iconv('UTF-8', 'UCS-4LE', $character))[1];
16 }
17
18 /**
19 * CHARACTER.
20 *
21 * @param string $character Value
22 *
23 * @return string
24 */
25 public static function CHARACTER($character)
26 {
27 $character = Functions::flattenSingleValue($character);
28
29 if ((!is_numeric($character)) || ($character < 0)) {
30 return Functions::VALUE();
31 }
32
33 if (function_exists('iconv')) {
34 return iconv('UCS-4LE', 'UTF-8', pack('V', $character));
35 }
36
37 return mb_convert_encoding('&#' . (int) $character . ';', 'UTF-8', 'HTML-ENTITIES');
38 }
39
40 /**
41 * TRIMNONPRINTABLE.
42 *
43 * @param mixed $stringValue Value to check
44 *
45 * @return string
46 */
47 public static function TRIMNONPRINTABLE($stringValue = '')
48 {
49 $stringValue = Functions::flattenSingleValue($stringValue);
50
51 if (is_bool($stringValue)) {
52 return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
53 }
54
55 if (self::$invalidChars == null) {
56 self::$invalidChars = range(chr(0), chr(31));
57 }
58
59 if (is_string($stringValue) || is_numeric($stringValue)) {
60 return str_replace(self::$invalidChars, '', trim($stringValue, "\x00..\x1F"));
61 }
62
63 return null;
64 }
65
66 /**
67 * TRIMSPACES.
68 *
69 * @param mixed $stringValue Value to check
70 *
71 * @return string
72 */
73 public static function TRIMSPACES($stringValue = '')
74 {
75 $stringValue = Functions::flattenSingleValue($stringValue);
76 if (is_bool($stringValue)) {
77 return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
78 }
79
80 if (is_string($stringValue) || is_numeric($stringValue)) {
81 return trim(preg_replace('/ +/', ' ', trim($stringValue, ' ')), ' ');
82 }
83
84 return null;
85 }
86
87 /**
88 * ASCIICODE.
89 *
90 * @param string $characters Value
91 *
92 * @return int
93 */
94 public static function ASCIICODE($characters)
95 {
96 if (($characters === null) || ($characters === '')) {
97 return Functions::VALUE();
98 }
99 $characters = Functions::flattenSingleValue($characters);
100 if (is_bool($characters)) {
101 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
102 $characters = (int) $characters;
103 } else {
104 $characters = ($characters) ? Calculation::getTRUE() : Calculation::getFALSE();
105 }
106 }
107
108 $character = $characters;
109 if (mb_strlen($characters, 'UTF-8') > 1) {
110 $character = mb_substr($characters, 0, 1, 'UTF-8');
111 }
112
113 return self::unicodeToOrd($character);
114 }
115
116 /**
117 * CONCATENATE.
118 *
119 * @return string
120 */
121 public static function CONCATENATE(...$args)
122 {
123 $returnValue = '';
124
125 // Loop through arguments
126 $aArgs = Functions::flattenArray($args);
127 foreach ($aArgs as $arg) {
128 if (is_bool($arg)) {
129 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
130 $arg = (int) $arg;
131 } else {
132 $arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
133 }
134 }
135 $returnValue .= $arg;
136 }
137
138 return $returnValue;
139 }
140
141 /**
142 * DOLLAR.
143 *
144 * This function converts a number to text using currency format, with the decimals rounded to the specified place.
145 * The format used is $#,##0.00_);($#,##0.00)..
146 *
147 * @param float $value The value to format
148 * @param int $decimals The number of digits to display to the right of the decimal point.
149 * If decimals is negative, number is rounded to the left of the decimal point.
150 * If you omit decimals, it is assumed to be 2
151 *
152 * @return string
153 */
154 public static function DOLLAR($value = 0, $decimals = 2)
155 {
156 $value = Functions::flattenSingleValue($value);
157 $decimals = $decimals === null ? 0 : Functions::flattenSingleValue($decimals);
158
159 // Validate parameters
160 if (!is_numeric($value) || !is_numeric($decimals)) {
161 return Functions::NAN();
162 }
163 $decimals = floor($decimals);
164
165 $mask = '$#,##0';
166 if ($decimals > 0) {
167 $mask .= '.' . str_repeat('0', $decimals);
168 } else {
169 $round = pow(10, abs($decimals));
170 if ($value < 0) {
171 $round = 0 - $round;
172 }
173 $value = MathTrig::MROUND($value, $round);
174 }
175
176 return NumberFormat::toFormattedString($value, $mask);
177 }
178
179 /**
180 * SEARCHSENSITIVE.
181 *
182 * @param string $needle The string to look for
183 * @param string $haystack The string in which to look
184 * @param int $offset Offset within $haystack
185 *
186 * @return string
187 */
188 public static function SEARCHSENSITIVE($needle, $haystack, $offset = 1)
189 {
190 $needle = Functions::flattenSingleValue($needle);
191 $haystack = Functions::flattenSingleValue($haystack);
192 $offset = Functions::flattenSingleValue($offset);
193
194 if (!is_bool($needle)) {
195 if (is_bool($haystack)) {
196 $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE();
197 }
198
199 if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
200 if (StringHelper::countCharacters($needle) == 0) {
201 return $offset;
202 }
203
204 $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8');
205 if ($pos !== false) {
206 return ++$pos;
207 }
208 }
209 }
210
211 return Functions::VALUE();
212 }
213
214 /**
215 * SEARCHINSENSITIVE.
216 *
217 * @param string $needle The string to look for
218 * @param string $haystack The string in which to look
219 * @param int $offset Offset within $haystack
220 *
221 * @return string
222 */
223 public static function SEARCHINSENSITIVE($needle, $haystack, $offset = 1)
224 {
225 $needle = Functions::flattenSingleValue($needle);
226 $haystack = Functions::flattenSingleValue($haystack);
227 $offset = Functions::flattenSingleValue($offset);
228
229 if (!is_bool($needle)) {
230 if (is_bool($haystack)) {
231 $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE();
232 }
233
234 if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
235 if (StringHelper::countCharacters($needle) == 0) {
236 return $offset;
237 }
238
239 $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8');
240 if ($pos !== false) {
241 return ++$pos;
242 }
243 }
244 }
245
246 return Functions::VALUE();
247 }
248
249 /**
250 * FIXEDFORMAT.
251 *
252 * @param mixed $value Value to check
253 * @param int $decimals
254 * @param bool $no_commas
255 *
256 * @return string
257 */
258 public static function FIXEDFORMAT($value, $decimals = 2, $no_commas = false)
259 {
260 $value = Functions::flattenSingleValue($value);
261 $decimals = Functions::flattenSingleValue($decimals);
262 $no_commas = Functions::flattenSingleValue($no_commas);
263
264 // Validate parameters
265 if (!is_numeric($value) || !is_numeric($decimals)) {
266 return Functions::NAN();
267 }
268 $decimals = floor($decimals);
269
270 $valueResult = round($value, $decimals);
271 if ($decimals < 0) {
272 $decimals = 0;
273 }
274 if (!$no_commas) {
275 $valueResult = number_format($valueResult, $decimals);
276 }
277
278 return (string) $valueResult;
279 }
280
281 /**
282 * LEFT.
283 *
284 * @param string $value Value
285 * @param int $chars Number of characters
286 *
287 * @return string
288 */
289 public static function LEFT($value = '', $chars = 1)
290 {
291 $value = Functions::flattenSingleValue($value);
292 $chars = Functions::flattenSingleValue($chars);
293
294 if ($chars < 0) {
295 return Functions::VALUE();
296 }
297
298 if (is_bool($value)) {
299 $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
300 }
301
302 return mb_substr($value, 0, $chars, 'UTF-8');
303 }
304
305 /**
306 * MID.
307 *
308 * @param string $value Value
309 * @param int $start Start character
310 * @param int $chars Number of characters
311 *
312 * @return string
313 */
314 public static function MID($value = '', $start = 1, $chars = null)
315 {
316 $value = Functions::flattenSingleValue($value);
317 $start = Functions::flattenSingleValue($start);
318 $chars = Functions::flattenSingleValue($chars);
319
320 if (($start < 1) || ($chars < 0)) {
321 return Functions::VALUE();
322 }
323
324 if (is_bool($value)) {
325 $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
326 }
327
328 if (empty($chars)) {
329 return '';
330 }
331
332 return mb_substr($value, --$start, $chars, 'UTF-8');
333 }
334
335 /**
336 * RIGHT.
337 *
338 * @param string $value Value
339 * @param int $chars Number of characters
340 *
341 * @return string
342 */
343 public static function RIGHT($value = '', $chars = 1)
344 {
345 $value = Functions::flattenSingleValue($value);
346 $chars = Functions::flattenSingleValue($chars);
347
348 if ($chars < 0) {
349 return Functions::VALUE();
350 }
351
352 if (is_bool($value)) {
353 $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
354 }
355
356 return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8');
357 }
358
359 /**
360 * STRINGLENGTH.
361 *
362 * @param string $value Value
363 *
364 * @return int
365 */
366 public static function STRINGLENGTH($value = '')
367 {
368 $value = Functions::flattenSingleValue($value);
369
370 if (is_bool($value)) {
371 $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
372 }
373
374 return mb_strlen($value, 'UTF-8');
375 }
376
377 /**
378 * LOWERCASE.
379 *
380 * Converts a string value to upper case.
381 *
382 * @param string $mixedCaseString
383 *
384 * @return string
385 */
386 public static function LOWERCASE($mixedCaseString)
387 {
388 $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
389
390 if (is_bool($mixedCaseString)) {
391 $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
392 }
393
394 return StringHelper::strToLower($mixedCaseString);
395 }
396
397 /**
398 * UPPERCASE.
399 *
400 * Converts a string value to upper case.
401 *
402 * @param string $mixedCaseString
403 *
404 * @return string
405 */
406 public static function UPPERCASE($mixedCaseString)
407 {
408 $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
409
410 if (is_bool($mixedCaseString)) {
411 $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
412 }
413
414 return StringHelper::strToUpper($mixedCaseString);
415 }
416
417 /**
418 * PROPERCASE.
419 *
420 * Converts a string value to upper case.
421 *
422 * @param string $mixedCaseString
423 *
424 * @return string
425 */
426 public static function PROPERCASE($mixedCaseString)
427 {
428 $mixedCaseString = Functions::flattenSingleValue($mixedCaseString);
429
430 if (is_bool($mixedCaseString)) {
431 $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE();
432 }
433
434 return StringHelper::strToTitle($mixedCaseString);
435 }
436
437 /**
438 * REPLACE.
439 *
440 * @param string $oldText String to modify
441 * @param int $start Start character
442 * @param int $chars Number of characters
443 * @param string $newText String to replace in defined position
444 *
445 * @return string
446 */
447 public static function REPLACE($oldText, $start, $chars, $newText)
448 {
449 $oldText = Functions::flattenSingleValue($oldText);
450 $start = Functions::flattenSingleValue($start);
451 $chars = Functions::flattenSingleValue($chars);
452 $newText = Functions::flattenSingleValue($newText);
453
454 $left = self::LEFT($oldText, $start - 1);
455 $right = self::RIGHT($oldText, self::STRINGLENGTH($oldText) - ($start + $chars) + 1);
456
457 return $left . $newText . $right;
458 }
459
460 /**
461 * SUBSTITUTE.
462 *
463 * @param string $text Value
464 * @param string $fromText From Value
465 * @param string $toText To Value
466 * @param int $instance Instance Number
467 *
468 * @return string
469 */
470 public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0)
471 {
472 $text = Functions::flattenSingleValue($text);
473 $fromText = Functions::flattenSingleValue($fromText);
474 $toText = Functions::flattenSingleValue($toText);
475 $instance = floor(Functions::flattenSingleValue($instance));
476
477 if ($instance == 0) {
478 return str_replace($fromText, $toText, $text);
479 }
480
481 $pos = -1;
482 while ($instance > 0) {
483 $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8');
484 if ($pos === false) {
485 break;
486 }
487 --$instance;
488 }
489
490 if ($pos !== false) {
491 return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText);
492 }
493
494 return $text;
495 }
496
497 /**
498 * RETURNSTRING.
499 *
500 * @param mixed $testValue Value to check
501 *
502 * @return null|string
503 */
504 public static function RETURNSTRING($testValue = '')
505 {
506 $testValue = Functions::flattenSingleValue($testValue);
507
508 if (is_string($testValue)) {
509 return $testValue;
510 }
511
512 return null;
513 }
514
515 /**
516 * TEXTFORMAT.
517 *
518 * @param mixed $value Value to check
519 * @param string $format Format mask to use
520 *
521 * @return string
522 */
523 public static function TEXTFORMAT($value, $format)
524 {
525 $value = Functions::flattenSingleValue($value);
526 $format = Functions::flattenSingleValue($format);
527
528 if ((is_string($value)) && (!is_numeric($value)) && Date::isDateTimeFormatCode($format)) {
529 $value = DateTime::DATEVALUE($value);
530 }
531
532 return (string) NumberFormat::toFormattedString($value, $format);
533 }
534
535 /**
536 * VALUE.
537 *
538 * @param mixed $value Value to check
539 *
540 * @return bool
541 */
542 public static function VALUE($value = '')
543 {
544 $value = Functions::flattenSingleValue($value);
545
546 if (!is_numeric($value)) {
547 $numberValue = str_replace(
548 StringHelper::getThousandsSeparator(),
549 '',
550 trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode())
551 );
552 if (is_numeric($numberValue)) {
553 return (float) $numberValue;
554 }
555
556 $dateSetting = Functions::getReturnDateType();
557 Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
558
559 if (strpos($value, ':') !== false) {
560 $timeValue = DateTime::TIMEVALUE($value);
561 if ($timeValue !== Functions::VALUE()) {
562 Functions::setReturnDateType($dateSetting);
563
564 return $timeValue;
565 }
566 }
567 $dateValue = DateTime::DATEVALUE($value);
568 if ($dateValue !== Functions::VALUE()) {
569 Functions::setReturnDateType($dateSetting);
570
571 return $dateValue;
572 }
573 Functions::setReturnDateType($dateSetting);
574
575 return Functions::VALUE();
576 }
577
578 return (float) $value;
579 }
580
581 /**
582 * NUMBERVALUE.
583 *
584 * @param mixed $value Value to check
585 * @param string $decimalSeparator decimal separator, defaults to locale defined value
586 * @param string $groupSeparator group/thosands separator, defaults to locale defined value
587 *
588 * @return float|string
589 */
590 public static function NUMBERVALUE($value = '', $decimalSeparator = null, $groupSeparator = null)
591 {
592 $value = Functions::flattenSingleValue($value);
593 $decimalSeparator = Functions::flattenSingleValue($decimalSeparator);
594 $groupSeparator = Functions::flattenSingleValue($groupSeparator);
595
596 if (!is_numeric($value)) {
597 $decimalSeparator = empty($decimalSeparator) ? StringHelper::getDecimalSeparator() : $decimalSeparator;
598 $groupSeparator = empty($groupSeparator) ? StringHelper::getThousandsSeparator() : $groupSeparator;
599
600 $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator) . '/', $value, $matches, PREG_OFFSET_CAPTURE);
601 if ($decimalPositions > 1) {
602 return Functions::VALUE();
603 }
604 $decimalOffset = array_pop($matches[0])[1];
605 if (strpos($value, $groupSeparator, $decimalOffset) !== false) {
606 return Functions::VALUE();
607 }
608
609 $value = str_replace([$groupSeparator, $decimalSeparator], ['', '.'], $value);
610
611 // Handle the special case of trailing % signs
612 $percentageString = rtrim($value, '%');
613 if (!is_numeric($percentageString)) {
614 return Functions::VALUE();
615 }
616
617 $percentageAdjustment = strlen($value) - strlen($percentageString);
618 if ($percentageAdjustment) {
619 $value = (float) $percentageString;
620 $value /= pow(10, $percentageAdjustment * 2);
621 }
622 }
623
624 return (float) $value;
625 }
626
627 /**
628 * Compares two text strings and returns TRUE if they are exactly the same, FALSE otherwise.
629 * EXACT is case-sensitive but ignores formatting differences.
630 * Use EXACT to test text being entered into a document.
631 *
632 * @param $value1
633 * @param $value2
634 *
635 * @return bool
636 */
637 public static function EXACT($value1, $value2)
638 {
639 $value1 = Functions::flattenSingleValue($value1);
640 $value2 = Functions::flattenSingleValue($value2);
641
642 return (string) $value2 === (string) $value1;
643 }
644
645 /**
646 * TEXTJOIN.
647 *
648 * @param mixed $delimiter
649 * @param mixed $ignoreEmpty
650 * @param mixed $args
651 *
652 * @return string
653 */
654 public static function TEXTJOIN($delimiter, $ignoreEmpty, ...$args)
655 {
656 // Loop through arguments
657 $aArgs = Functions::flattenArray($args);
658 foreach ($aArgs as $key => &$arg) {
659 if ($ignoreEmpty && trim($arg) == '') {
660 unset($aArgs[$key]);
661 } elseif (is_bool($arg)) {
662 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
663 $arg = (int) $arg;
664 } else {
665 $arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
666 }
667 }
668 }
669
670 return implode($delimiter, $aArgs);
671 }
672 }
673