Completed
Push — master ( fe79f7...a3187a )
by Mark
36s queued 32s
created

Text::buildDelimiter()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 17
ccs 9
cts 9
cp 1
rs 9.9666
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\TextData;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
7
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
8
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
9
10
class Text
11
{
12
    use ArrayEnabled;
13
14
    /**
15
     * LEN.
16
     *
17
     * @param mixed $value String Value
18
     *                         Or can be an array of values
19
     *
20
     * @return array|int
21
     *         If an array of values is passed for the argument, then the returned result
22
     *            will also be an array with matching dimensions
23
     */
24 45
    public static function length($value = '')
25
    {
26 45
        if (is_array($value)) {
27 8
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
28
        }
29
30 45
        $value = Helpers::extractString($value);
31
32 45
        return mb_strlen($value ?? '', 'UTF-8');
33
    }
34
35
    /**
36
     * Compares two text strings and returns TRUE if they are exactly the same, FALSE otherwise.
37
     * EXACT is case-sensitive but ignores formatting differences.
38
     * Use EXACT to test text being entered into a document.
39
     *
40
     * @param mixed $value1 String Value
41
     *                         Or can be an array of values
42
     * @param mixed $value2 String Value
43
     *                         Or can be an array of values
44
     *
45
     * @return array|bool
46
     *         If an array of values is passed for either of the arguments, then the returned result
47
     *            will also be an array with matching dimensions
48
     */
49 13
    public static function exact($value1, $value2)
50
    {
51 13
        if (is_array($value1) || is_array($value2)) {
52 10
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $value1, $value2);
53
        }
54
55 13
        $value1 = Helpers::extractString($value1);
56 13
        $value2 = Helpers::extractString($value2);
57
58 13
        return $value2 === $value1;
59
    }
60
61
    /**
62
     * RETURNSTRING.
63
     *
64
     * @param mixed $testValue Value to check
65
     *                         Or can be an array of values
66
     *
67
     * @return null|array|string
68
     *         If an array of values is passed for the argument, then the returned result
69
     *            will also be an array with matching dimensions
70
     */
71 8
    public static function test($testValue = '')
72
    {
73 8
        if (is_array($testValue)) {
74 3
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $testValue);
75
        }
76
77 8
        if (is_string($testValue)) {
78 5
            return $testValue;
79
        }
80
81 6
        return null;
82
    }
83
84
    /**
85
     * TEXTSPLIT.
86
     *
87
     * @param mixed $text the text that you're searching
88
     * @param null|array|string $columnDelimiter The text that marks the point where to spill the text across columns.
89
     *                          Multiple delimiters can be passed as an array of string values
90
     * @param null|array|string $rowDelimiter The text that marks the point where to spill the text down rows.
91
     *                          Multiple delimiters can be passed as an array of string values
92
     * @param bool $ignoreEmpty Specify FALSE to create an empty cell when two delimiters are consecutive.
93
     *                              true = create empty cells
94
     *                              false = skip empty cells
95
     *                              Defaults to TRUE, which creates an empty cell
96
     * @param bool $matchMode Determines whether the match is case-sensitive or not.
97
     *                              true = case-sensitive
98
     *                              false = case-insensitive
99
     *                         By default, a case-sensitive match is done.
100
     * @param mixed $padding The value with which to pad the result.
101
     *                              The default is #N/A.
102
     *
103
     * @return array the array built from the text, split by the row and column delimiters
104
     */
105 10
    public static function split($text, $columnDelimiter = null, $rowDelimiter = null, bool $ignoreEmpty = false, bool $matchMode = true, $padding = '#N/A')
106
    {
107 10
        $text = Functions::flattenSingleValue($text);
108
109 10
        $flags = self::matchFlags($matchMode);
110
111 10
        if ($rowDelimiter !== null) {
112 10
            $delimiter = self::buildDelimiter($rowDelimiter);
113 10
            $rows = ($delimiter === '()')
114 4
                ? [$text]
115 10
                : preg_split("/{$delimiter}/{$flags}", $text);
116
        } else {
117
            $rows = [$text];
118
        }
119
120
        /** @var array $rows */
121 10
        if ($ignoreEmpty === true) {
122 1
            $rows = array_values(array_filter(
123
                $rows,
124 1
                function ($row) {
125 1
                    return $row !== '';
126
                }
127
            ));
128
        }
129
130 10
        if ($columnDelimiter !== null) {
131 10
            $delimiter = self::buildDelimiter($columnDelimiter);
132 10
            array_walk(
133
                $rows,
134 10
                function (&$row) use ($delimiter, $flags, $ignoreEmpty): void {
135 10
                    $row = ($delimiter === '()')
136 2
                        ? [$row]
137 10
                        : preg_split("/{$delimiter}/{$flags}", $row);
138
                    /** @var array $row */
139 10
                    if ($ignoreEmpty === true) {
140 1
                        $row = array_values(array_filter(
141
                            $row,
142 1
                            function ($value) {
143 1
                                return $value !== '';
144
                            }
145
                        ));
146
                    }
147
                }
148
            );
149 10
            if ($ignoreEmpty === true) {
150 1
                $rows = array_values(array_filter(
151
                    $rows,
152 1
                    function ($row) {
153 1
                        return $row !== [] && $row !== [''];
154
                    }
155
                ));
156
            }
157
        }
158
159 10
        return self::applyPadding($rows, $padding);
160
    }
161
162
    /**
163
     * @param mixed $padding
164
     */
165 10
    private static function applyPadding(array $rows, $padding): array
166
    {
167 10
        $columnCount = array_reduce(
168
            $rows,
169 10
            function (int $counter, array $row): int {
170 10
                return max($counter, count($row));
171
            },
172
            0
173
        );
174
175 10
        return array_map(
176 10
            function (array $row) use ($columnCount, $padding): array {
177 10
                return (count($row) < $columnCount)
178 2
                    ? array_merge($row, array_fill(0, $columnCount - count($row), $padding))
179 10
                    : $row;
180
            },
181
            $rows
182
        );
183
    }
184
185
    /**
186
     * @param null|array|string $delimiter the text that marks the point before which you want to split
187
     *                                 Multiple delimiters can be passed as an array of string values
188
     */
189 10
    private static function buildDelimiter($delimiter): string
190
    {
191 10
        $valueSet = Functions::flattenArray($delimiter);
192
193 10
        if (is_array($delimiter) && count($valueSet) > 1) {
194 3
            $quotedDelimiters = array_map(
195 3
                function ($delimiter) {
196 3
                    return preg_quote($delimiter ?? '');
197
                },
198
                $valueSet
199
            );
200 3
            $delimiters = implode('|', $quotedDelimiters);
201
202 3
            return '(' . $delimiters . ')';
203
        }
204
205 10
        return '(' . preg_quote(Functions::flattenSingleValue($delimiter)) . ')';
1 ignored issue
show
Bug introduced by
It seems like PhpOffice\PhpSpreadsheet...SingleValue($delimiter) can also be of type array and null; however, parameter $str of preg_quote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
        return '(' . preg_quote(/** @scrutinizer ignore-type */ Functions::flattenSingleValue($delimiter)) . ')';
Loading history...
206
    }
207
208 10
    private static function matchFlags(bool $matchMode): string
209
    {
210 10
        return ($matchMode === true) ? 'miu' : 'mu';
211
    }
212
213 2
    public static function fromArray(array $array, int $format = 0): string
214
    {
215 2
        $result = [];
216 2
        foreach ($array as $row) {
217 2
            $cells = [];
218 2
            foreach ($row as $cellValue) {
219 2
                $value = ($format === 1) ? self::formatValueMode1($cellValue) : self::formatValueMode0($cellValue);
220 2
                $cells[] = $value;
221
            }
222 2
            $result[] = implode(($format === 1) ? ',' : ', ', $cells);
223
        }
224
225 2
        $result = implode(($format === 1) ? ';' : ', ', $result);
226
227 2
        return ($format === 1) ? '{' . $result . '}' : $result;
228
    }
229
230
    /**
231
     * @param mixed $cellValue
232
     */
233 1
    private static function formatValueMode0($cellValue): string
234
    {
235 1
        if (is_bool($cellValue)) {
236 1
            return Calculation::getLocaleBoolean($cellValue ? 'TRUE' : 'FALSE');
237
        }
238
239 1
        return (string) $cellValue;
240
    }
241
242
    /**
243
     * @param mixed $cellValue
244
     */
245 1
    private static function formatValueMode1($cellValue): string
246
    {
247 1
        if (is_string($cellValue) && ErrorValue::isError($cellValue) === false) {
248 1
            return Calculation::FORMULA_STRING_QUOTE . $cellValue . Calculation::FORMULA_STRING_QUOTE;
249 1
        } elseif (is_bool($cellValue)) {
250 1
            return Calculation::getLocaleBoolean($cellValue ? 'TRUE' : 'FALSE');
251
        }
252
253 1
        return (string) $cellValue;
254
    }
255
}
256