Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
 
5
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
6
 
7
class BinaryComparison
8
{
9
    /**
10
     * Epsilon Precision used for comparisons in calculations.
11
     */
12
    private const DELTA = 0.1e-12;
13
 
14
    /**
15
     * Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters.
16
     *
17
     * @param null|string $str1 First string value for the comparison
18
     * @param null|string $str2 Second string value for the comparison
19
     */
20
    private static function strcmpLowercaseFirst(?string $str1, ?string $str2): int
21
    {
22
        $inversedStr1 = StringHelper::strCaseReverse($str1 ?? '');
23
        $inversedStr2 = StringHelper::strCaseReverse($str2 ?? '');
24
 
25
        return strcmp($inversedStr1, $inversedStr2);
26
    }
27
 
28
    /**
29
     * PHP8.1 deprecates passing null to strcmp.
30
     *
31
     * @param null|string $str1 First string value for the comparison
32
     * @param null|string $str2 Second string value for the comparison
33
     */
34
    private static function strcmpAllowNull(?string $str1, ?string $str2): int
35
    {
36
        return strcmp($str1 ?? '', $str2 ?? '');
37
    }
38
 
39
    public static function compare(mixed $operand1, mixed $operand2, string $operator): bool
40
    {
41
        //    Simple validate the two operands if they are string values
42
        if (is_string($operand1) && $operand1 > '' && $operand1[0] == Calculation::FORMULA_STRING_QUOTE) {
43
            $operand1 = Calculation::unwrapResult($operand1);
44
        }
45
        if (is_string($operand2) && $operand2 > '' && $operand2[0] == Calculation::FORMULA_STRING_QUOTE) {
46
            $operand2 = Calculation::unwrapResult($operand2);
47
        }
48
 
49
        // Use case insensitive comparaison if not OpenOffice mode
50
        if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) {
51
            if (is_string($operand1)) {
52
                $operand1 = StringHelper::strToUpper($operand1);
53
            }
54
            if (is_string($operand2)) {
55
                $operand2 = StringHelper::strToUpper($operand2);
56
            }
57
        }
58
 
59
        $useLowercaseFirstComparison = is_string($operand1)
60
            && is_string($operand2)
61
            && Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE;
62
 
63
        return self::evaluateComparison($operand1, $operand2, $operator, $useLowercaseFirstComparison);
64
    }
65
 
66
    private static function evaluateComparison(mixed $operand1, mixed $operand2, string $operator, bool $useLowercaseFirstComparison): bool
67
    {
68
        return match ($operator) {
69
            '=' => self::equal($operand1, $operand2),
70
            '>' => self::greaterThan($operand1, $operand2, $useLowercaseFirstComparison),
71
            '<' => self::lessThan($operand1, $operand2, $useLowercaseFirstComparison),
72
            '>=' => self::greaterThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison),
73
            '<=' => self::lessThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison),
74
            '<>' => self::notEqual($operand1, $operand2),
75
            default => throw new Exception('Unsupported binary comparison operator'),
76
        };
77
    }
78
 
79
    private static function equal(mixed $operand1, mixed $operand2): bool
80
    {
81
        if (is_numeric($operand1) && is_numeric($operand2)) {
82
            $result = (abs($operand1 - $operand2) < self::DELTA);
83
        } elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
84
            $result = $operand1 == $operand2;
85
        } else {
86
            $result = self::strcmpAllowNull($operand1, $operand2) == 0;
87
        }
88
 
89
        return $result;
90
    }
91
 
92
    private static function greaterThanOrEqual(mixed $operand1, mixed $operand2, bool $useLowercaseFirstComparison): bool
93
    {
94
        if (is_numeric($operand1) && is_numeric($operand2)) {
95
            $result = ((abs($operand1 - $operand2) < self::DELTA) || ($operand1 > $operand2));
96
        } elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
97
            $result = $operand1 >= $operand2;
98
        } elseif ($useLowercaseFirstComparison) {
99
            $result = self::strcmpLowercaseFirst($operand1, $operand2) >= 0;
100
        } else {
101
            $result = self::strcmpAllowNull($operand1, $operand2) >= 0;
102
        }
103
 
104
        return $result;
105
    }
106
 
107
    private static function lessThanOrEqual(mixed $operand1, mixed $operand2, bool $useLowercaseFirstComparison): bool
108
    {
109
        if (is_numeric($operand1) && is_numeric($operand2)) {
110
            $result = ((abs($operand1 - $operand2) < self::DELTA) || ($operand1 < $operand2));
111
        } elseif (($operand1 === null && is_numeric($operand2)) || ($operand2 === null && is_numeric($operand1))) {
112
            $result = $operand1 <= $operand2;
113
        } elseif ($useLowercaseFirstComparison) {
114
            $result = self::strcmpLowercaseFirst($operand1, $operand2) <= 0;
115
        } else {
116
            $result = self::strcmpAllowNull($operand1, $operand2) <= 0;
117
        }
118
 
119
        return $result;
120
    }
121
 
122
    private static function greaterThan(mixed $operand1, mixed $operand2, bool $useLowercaseFirstComparison): bool
123
    {
124
        return self::lessThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison) !== true;
125
    }
126
 
127
    private static function lessThan(mixed $operand1, mixed $operand2, bool $useLowercaseFirstComparison): bool
128
    {
129
        return self::greaterThanOrEqual($operand1, $operand2, $useLowercaseFirstComparison) !== true;
130
    }
131
 
132
    private static function notEqual(mixed $operand1, mixed $operand2): bool
133
    {
134
        return self::equal($operand1, $operand2) !== true;
135
    }
136
}