PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / libraries / vendor / PhpSpreadsheet / Calculation / TextData / Extract.php

Extract.php in TablePress – Tables in WordPress made easy 3.4, at libraries/vendor/PhpSpreadsheet/Calculation/TextData/Extract.php

291 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TablePress\PhpOffice\PhpSpreadsheet\Calculation\TextData;
4
5 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Functions;
8 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
9 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper;
10
11 class Extract
12 {
13 use ArrayEnabled;
14
15 /**
16 * LEFT.
17 *
18 * @param mixed $value String value from which to extract characters
19 * Or can be an array of values
20 * @param mixed $chars The number of characters to extract (as an integer)
21 * Or can be an array of values
22 *
23 * @return array<mixed>|string The joined string
24 * If an array of values is passed for the $value or $chars arguments, then the returned result
25 * will also be an array with matching dimensions
26 */
27 public static function left($value, $chars = 1)
28 {
29 if (is_array($value) || is_array($chars)) {
30 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $chars);
31 }
32
33 try {
34 $value = Helpers::extractString($value, true);
35 $chars = Helpers::extractInt($chars, 0, 1);
36 } catch (CalcExp $e) {
37 return $e->getMessage();
38 }
39
40 return mb_substr($value, 0, $chars, 'UTF-8');
41 }
42
43 /**
44 * MID.
45 *
46 * @param mixed $value String value from which to extract characters
47 * Or can be an array of values
48 * @param mixed $start Integer offset of the first character that we want to extract
49 * Or can be an array of values
50 * @param mixed $chars The number of characters to extract (as an integer)
51 * Or can be an array of values
52 *
53 * @return array<mixed>|string The joined string
54 * If an array of values is passed for the $value, $start or $chars arguments, then the returned result
55 * will also be an array with matching dimensions
56 */
57 public static function mid($value, $start, $chars)
58 {
59 if (is_array($value) || is_array($start) || is_array($chars)) {
60 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $start, $chars);
61 }
62
63 try {
64 $value = Helpers::extractString($value, true);
65 $start = Helpers::extractInt($start, 1);
66 $chars = Helpers::extractInt($chars, 0);
67 } catch (CalcExp $e) {
68 return $e->getMessage();
69 }
70
71 return mb_substr($value, --$start, $chars, 'UTF-8');
72 }
73
74 /**
75 * RIGHT.
76 *
77 * @param mixed $value String value from which to extract characters
78 * Or can be an array of values
79 * @param mixed $chars The number of characters to extract (as an integer)
80 * Or can be an array of values
81 *
82 * @return array<mixed>|string The joined string
83 * If an array of values is passed for the $value or $chars arguments, then the returned result
84 * will also be an array with matching dimensions
85 */
86 public static function right($value, $chars = 1)
87 {
88 if (is_array($value) || is_array($chars)) {
89 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $chars);
90 }
91
92 try {
93 $value = Helpers::extractString($value, true);
94 $chars = Helpers::extractInt($chars, 0, 1);
95 } catch (CalcExp $e) {
96 return $e->getMessage();
97 }
98
99 return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8');
100 }
101
102 /**
103 * TEXTBEFORE.
104 *
105 * @param mixed $text the text that you're searching
106 * Or can be an array of values
107 * @param null|array<string>|string $delimiter the text that marks the point before which you want to extract
108 * Multiple delimiters can be passed as an array of string values
109 * @param mixed $instance The instance of the delimiter after which you want to extract the text.
110 * By default, this is the first instance (1).
111 * A negative value means start searching from the end of the text string.
112 * Or can be an array of values
113 * @param mixed $matchMode Determines whether the match is case-sensitive or not.
114 * 0 - Case-sensitive
115 * 1 - Case-insensitive
116 * Or can be an array of values
117 * @param mixed $matchEnd Treats the end of text as a delimiter.
118 * 0 - Don't match the delimiter against the end of the text.
119 * 1 - Match the delimiter against the end of the text.
120 * Or can be an array of values
121 * @param mixed $ifNotFound value to return if no match is found
122 * The default is a #N/A Error
123 * Or can be an array of values
124 *
125 * @return array<mixed>|string the string extracted from text before the delimiter; or the $ifNotFound value
126 * If an array of values is passed for any of the arguments, then the returned result
127 * will also be an array with matching dimensions
128 */
129 public static function before($text, $delimiter, $instance = 1, $matchMode = 0, $matchEnd = 0, $ifNotFound = '#N/A')
130 {
131 if (is_array($text) || is_array($instance) || is_array($matchMode) || is_array($matchEnd) || is_array($ifNotFound)) {
132 return self::evaluateArrayArgumentsIgnore([self::class, __FUNCTION__], 1, $text, $delimiter, $instance, $matchMode, $matchEnd, $ifNotFound);
133 }
134
135 try {
136 $text = Helpers::extractString($text ?? '', true);
137 Helpers::extractString(Functions::flattenSingleValue($delimiter ?? ''), true);
138 } catch (CalcExp $e) {
139 return $e->getMessage();
140 }
141
142 $instance = (int) StringHelper::convertToString($instance);
143 $matchMode = (int) StringHelper::convertToString($matchMode);
144 $matchEnd = (int) StringHelper::convertToString($matchEnd);
145
146 $split = self::validateTextBeforeAfter($text, $delimiter, $instance, $matchMode, $matchEnd, $ifNotFound);
147 if (is_string($split)) {
148 return $split;
149 }
150 if (Helpers::extractString(Functions::flattenSingleValue($delimiter ?? '')) === '') {
151 return ($instance > 0) ? '' : $text;
152 }
153
154 // Adjustment for a match as the first element of the split
155 $flags = self::matchFlags($matchMode);
156 $delimiter = self::buildDelimiter($delimiter);
157 $adjust = preg_match('/^' . $delimiter . "\$/{$flags}", $split[0]);
158 $oddReverseAdjustment = count($split) % 2;
159
160 $split = ($instance < 0)
161 ? array_slice($split, 0, max(count($split) - (abs($instance) * 2 - 1) - $adjust - $oddReverseAdjustment, 0))
162 : array_slice($split, 0, $instance * 2 - 1 - $adjust);
163
164 return implode('', $split);
165 }
166
167 /**
168 * TEXTAFTER.
169 *
170 * @param mixed $text the text that you're searching
171 * @param null|array<string>|string $delimiter the text that marks the point before which you want to extract
172 * Multiple delimiters can be passed as an array of string values
173 * @param mixed $instance The instance of the delimiter after which you want to extract the text.
174 * By default, this is the first instance (1).
175 * A negative value means start searching from the end of the text string.
176 * Or can be an array of values
177 * @param mixed $matchMode Determines whether the match is case-sensitive or not.
178 * 0 - Case-sensitive
179 * 1 - Case-insensitive
180 * Or can be an array of values
181 * @param mixed $matchEnd Treats the end of text as a delimiter.
182 * 0 - Don't match the delimiter against the end of the text.
183 * 1 - Match the delimiter against the end of the text.
184 * Or can be an array of values
185 * @param mixed $ifNotFound value to return if no match is found
186 * The default is a #N/A Error
187 * Or can be an array of values
188 *
189 * @return array<mixed>|string the string extracted from text before the delimiter; or the $ifNotFound value
190 * If an array of values is passed for any of the arguments, then the returned result
191 * will also be an array with matching dimensions
192 */
193 public static function after($text, $delimiter, $instance = 1, $matchMode = 0, $matchEnd = 0, $ifNotFound = '#N/A')
194 {
195 if (is_array($text) || is_array($instance) || is_array($matchMode) || is_array($matchEnd) || is_array($ifNotFound)) {
196 return self::evaluateArrayArgumentsIgnore([self::class, __FUNCTION__], 1, $text, $delimiter, $instance, $matchMode, $matchEnd, $ifNotFound);
197 }
198
199 try {
200 $text = Helpers::extractString($text ?? '', true);
201 Helpers::extractString(Functions::flattenSingleValue($delimiter ?? ''), true);
202 } catch (CalcExp $e) {
203 return $e->getMessage();
204 }
205
206 $instance = (int) StringHelper::convertToString($instance);
207 $matchMode = (int) StringHelper::convertToString($matchMode);
208 $matchEnd = (int) StringHelper::convertToString($matchEnd);
209
210 $split = self::validateTextBeforeAfter($text, $delimiter, $instance, $matchMode, $matchEnd, $ifNotFound);
211 if (is_string($split)) {
212 return $split;
213 }
214 if (Helpers::extractString(Functions::flattenSingleValue($delimiter ?? '')) === '') {
215 return ($instance < 0) ? '' : $text;
216 }
217
218 // Adjustment for a match as the first element of the split
219 $flags = self::matchFlags($matchMode);
220 $delimiter = self::buildDelimiter($delimiter);
221 $adjust = preg_match('/^' . $delimiter . "\$/{$flags}", $split[0]);
222 $oddReverseAdjustment = count($split) % 2;
223
224 $split = ($instance < 0)
225 ? array_slice($split, count($split) - ((int) abs($instance + 1) * 2) - $adjust - $oddReverseAdjustment)
226 : array_slice($split, $instance * 2 - $adjust);
227
228 return implode('', $split);
229 }
230
231 /**
232 * @param null|array<string>|string $delimiter
233 * @param mixed $ifNotFound
234 *
235 * @return array<string>|string
236 */
237 private static function validateTextBeforeAfter(string $text, $delimiter, int $instance, int $matchMode, int $matchEnd, $ifNotFound)
238 {
239 $flags = self::matchFlags($matchMode);
240 $delimiter = self::buildDelimiter($delimiter);
241
242 if (preg_match('/' . $delimiter . "/{$flags}", $text) === 0 && $matchEnd === 0) {
243 return is_array($ifNotFound) ? $ifNotFound : StringHelper::convertToString($ifNotFound);
244 }
245
246 $split = preg_split('/' . $delimiter . "/{$flags}", $text, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
247 if ($split === false) {
248 return ExcelError::NA();
249 }
250
251 if ($instance === 0 || abs($instance) > StringHelper::countCharacters($text)) {
252 return ExcelError::VALUE();
253 }
254
255 if ($matchEnd === 0 && (abs($instance) > floor(count($split) / 2))) {
256 return ExcelError::NA();
257 } elseif ($matchEnd !== 0 && (abs($instance) - 1 > ceil(count($split) / 2))) {
258 return ExcelError::NA();
259 }
260
261 return $split;
262 }
263
264 /**
265 * @param null|array<string>|string $delimiter the text that marks the point before which you want to extract
266 * Multiple delimiters can be passed as an array of string values
267 */
268 private static function buildDelimiter($delimiter): string
269 {
270 if (is_array($delimiter)) {
271 /** @var array<?string> */
272 $delimiter = Functions::flattenArray($delimiter);
273 $quotedDelimiters = array_map(
274 fn (?string $delimiter): string => preg_quote($delimiter ?? '', '/'),
275 $delimiter
276 );
277 $delimiters = implode('|', $quotedDelimiters);
278
279 return '(' . $delimiters . ')';
280 }
281 /** @var ?string $delimiter */
282
283 return '(' . preg_quote($delimiter ?? '', '/') . ')';
284 }
285
286 private static function matchFlags(int $matchMode): string
287 {
288 return ($matchMode === 0) ? 'mu' : 'miu';
289 }
290 }
291