Completed
Push — develop ( 47d726...7b90bb )
by Adrien
17:12
created

StringHelper   F

Complexity

Total Complexity 77

Size/Duplication

Total Lines 752
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 1

Test Coverage

Coverage 35.95%

Importance

Changes 0
Metric Value
dl 0
loc 752
ccs 114
cts 317
cp 0.3595
rs 1.7391
c 0
b 0
f 0
wmc 77
lcom 5
cbo 1

30 Methods

Rating   Name   Duplication   Size   Complexity  
B buildControlCharacters() 0 10 5
B buildSYLKCharacters() 0 161 1
C getIsIconvEnabled() 0 40 11
A buildCharacterSets() 0 9 3
A controlCharacterOOXML2PHP() 0 4 1
A controlCharacterPHP2OOXML() 0 4 1
A sanitizeUTF8() 0 12 2
A isUTF8() 0 4 2
A formatNumber() 0 8 2
A UTF8toBIFF8UnicodeShort() 0 22 3
A UTF8toBIFF8UnicodeLong() 0 12 1
A convertEncoding() 0 8 2
A countCharacters() 0 4 1
A substring() 0 4 1
A strToUpper() 0 4 1
A strToLower() 0 4 1
A strToTitle() 0 4 1
A mbIsUpper() 0 4 1
A mbStrSplit() 0 6 1
D mbStrReplace() 0 25 9
A strCaseReverse() 0 13 3
A convertToNumberIfFraction() 0 12 3
A getDecimalSeparator() 0 15 4
A setDecimalSeparator() 0 4 1
A getThousandsSeparator() 0 15 4
A setThousandsSeparator() 0 4 1
A getCurrencyCode() 0 20 4
A setCurrencyCode() 0 4 1
A SYLKtoUTF8() 0 13 3
A testStringAsNumeric() 0 9 3

How to fix   Complexity   

Complex Class

Complex classes like StringHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use StringHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Shared;
4
5
/**
6
 * Copyright (c) 2006 - 2016 PhpSpreadsheet.
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 *
22
 * @category   PhpSpreadsheet
23
 *
24
 * @copyright  Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
25
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
26
 */
27
class StringHelper
28
{
29
    /**    Constants                */
30
    /**    Regular Expressions        */
31
    //    Fraction
32
    const STRING_REGEXP_FRACTION = '(-?)(\d+)\s+(\d+\/\d+)';
33
34
    /**
35
     * Control characters array.
36
     *
37
     * @var string[]
38
     */
39
    private static $controlCharacters = [];
40
41
    /**
42
     * SYLK Characters array.
43
     *
44
     * @var array
45
     */
46
    private static $SYLKCharacters = [];
47
48
    /**
49
     * Decimal separator.
50
     *
51
     * @var string
52
     */
53
    private static $decimalSeparator;
54
55
    /**
56
     * Thousands separator.
57
     *
58
     * @var string
59
     */
60
    private static $thousandsSeparator;
61
62
    /**
63
     * Currency code.
64
     *
65
     * @var string
66
     */
67
    private static $currencyCode;
68
69
    /**
70
     * Is iconv extension avalable?
71
     *
72
     * @var bool
73
     */
74
    private static $isIconvEnabled;
75
76
    /**
77
     * Build control characters array.
78
     */
79
    private static function buildControlCharacters()
80
    {
81
        for ($i = 0; $i <= 31; ++$i) {
82
            if ($i != 9 && $i != 10 && $i != 13) {
83
                $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
84
                $replace = chr($i);
85
                self::$controlCharacters[$find] = $replace;
86
            }
87
        }
88
    }
89
90
    /**
91
     * Build SYLK characters array.
92
     */
93
    private static function buildSYLKCharacters()
94
    {
95
        self::$SYLKCharacters = [
96
            "\x1B 0" => chr(0),
97
            "\x1B 1" => chr(1),
98
            "\x1B 2" => chr(2),
99
            "\x1B 3" => chr(3),
100
            "\x1B 4" => chr(4),
101
            "\x1B 5" => chr(5),
102
            "\x1B 6" => chr(6),
103
            "\x1B 7" => chr(7),
104
            "\x1B 8" => chr(8),
105
            "\x1B 9" => chr(9),
106
            "\x1B :" => chr(10),
107
            "\x1B ;" => chr(11),
108
            "\x1B <" => chr(12),
109
            "\x1B =" => chr(13),
110
            "\x1B >" => chr(14),
111
            "\x1B ?" => chr(15),
112
            "\x1B!0" => chr(16),
113
            "\x1B!1" => chr(17),
114
            "\x1B!2" => chr(18),
115
            "\x1B!3" => chr(19),
116
            "\x1B!4" => chr(20),
117
            "\x1B!5" => chr(21),
118
            "\x1B!6" => chr(22),
119
            "\x1B!7" => chr(23),
120
            "\x1B!8" => chr(24),
121
            "\x1B!9" => chr(25),
122
            "\x1B!:" => chr(26),
123
            "\x1B!;" => chr(27),
124
            "\x1B!<" => chr(28),
125
            "\x1B!=" => chr(29),
126
            "\x1B!>" => chr(30),
127
            "\x1B!?" => chr(31),
128
            "\x1B'?" => chr(127),
129
            "\x1B(0" => '€', // 128 in CP1252
130
            "\x1B(2" => '‚', // 130 in CP1252
131
            "\x1B(3" => 'ƒ', // 131 in CP1252
132
            "\x1B(4" => '„', // 132 in CP1252
133
            "\x1B(5" => '…', // 133 in CP1252
134
            "\x1B(6" => '†', // 134 in CP1252
135
            "\x1B(7" => '‡', // 135 in CP1252
136
            "\x1B(8" => 'ˆ', // 136 in CP1252
137
            "\x1B(9" => '‰', // 137 in CP1252
138
            "\x1B(:" => 'Š', // 138 in CP1252
139
            "\x1B(;" => '‹', // 139 in CP1252
140
            "\x1BNj" => 'Œ', // 140 in CP1252
141
            "\x1B(>" => 'Ž', // 142 in CP1252
142
            "\x1B)1" => '‘', // 145 in CP1252
143
            "\x1B)2" => '’', // 146 in CP1252
144
            "\x1B)3" => '“', // 147 in CP1252
145
            "\x1B)4" => '”', // 148 in CP1252
146
            "\x1B)5" => '•', // 149 in CP1252
147
            "\x1B)6" => '–', // 150 in CP1252
148
            "\x1B)7" => '—', // 151 in CP1252
149
            "\x1B)8" => '˜', // 152 in CP1252
150
            "\x1B)9" => '™', // 153 in CP1252
151
            "\x1B):" => 'š', // 154 in CP1252
152
            "\x1B);" => '›', // 155 in CP1252
153
            "\x1BNz" => 'œ', // 156 in CP1252
154
            "\x1B)>" => 'ž', // 158 in CP1252
155
            "\x1B)?" => 'Ÿ', // 159 in CP1252
156
            "\x1B*0" => ' ', // 160 in CP1252
157
            "\x1BN!" => '¡', // 161 in CP1252
158
            "\x1BN\"" => '¢', // 162 in CP1252
159
            "\x1BN#" => '£', // 163 in CP1252
160
            "\x1BN(" => '¤', // 164 in CP1252
161
            "\x1BN%" => '¥', // 165 in CP1252
162
            "\x1B*6" => '¦', // 166 in CP1252
163
            "\x1BN'" => '§', // 167 in CP1252
164
            "\x1BNH " => '¨', // 168 in CP1252
165
            "\x1BNS" => '©', // 169 in CP1252
166
            "\x1BNc" => 'ª', // 170 in CP1252
167
            "\x1BN+" => '«', // 171 in CP1252
168
            "\x1B*<" => '¬', // 172 in CP1252
169
            "\x1B*=" => '­', // 173 in CP1252
170
            "\x1BNR" => '®', // 174 in CP1252
171
            "\x1B*?" => '¯', // 175 in CP1252
172
            "\x1BN0" => '°', // 176 in CP1252
173
            "\x1BN1" => '±', // 177 in CP1252
174
            "\x1BN2" => '²', // 178 in CP1252
175
            "\x1BN3" => '³', // 179 in CP1252
176
            "\x1BNB " => '´', // 180 in CP1252
177
            "\x1BN5" => 'µ', // 181 in CP1252
178
            "\x1BN6" => '¶', // 182 in CP1252
179
            "\x1BN7" => '·', // 183 in CP1252
180
            "\x1B+8" => '¸', // 184 in CP1252
181
            "\x1BNQ" => '¹', // 185 in CP1252
182
            "\x1BNk" => 'º', // 186 in CP1252
183
            "\x1BN;" => '»', // 187 in CP1252
184
            "\x1BN<" => '¼', // 188 in CP1252
185
            "\x1BN=" => '½', // 189 in CP1252
186
            "\x1BN>" => '¾', // 190 in CP1252
187
            "\x1BN?" => '¿', // 191 in CP1252
188
            "\x1BNAA" => 'À', // 192 in CP1252
189
            "\x1BNBA" => 'Á', // 193 in CP1252
190
            "\x1BNCA" => 'Â', // 194 in CP1252
191
            "\x1BNDA" => 'Ã', // 195 in CP1252
192
            "\x1BNHA" => 'Ä', // 196 in CP1252
193
            "\x1BNJA" => 'Å', // 197 in CP1252
194
            "\x1BNa" => 'Æ', // 198 in CP1252
195
            "\x1BNKC" => 'Ç', // 199 in CP1252
196
            "\x1BNAE" => 'È', // 200 in CP1252
197
            "\x1BNBE" => 'É', // 201 in CP1252
198
            "\x1BNCE" => 'Ê', // 202 in CP1252
199
            "\x1BNHE" => 'Ë', // 203 in CP1252
200
            "\x1BNAI" => 'Ì', // 204 in CP1252
201
            "\x1BNBI" => 'Í', // 205 in CP1252
202
            "\x1BNCI" => 'Î', // 206 in CP1252
203
            "\x1BNHI" => 'Ï', // 207 in CP1252
204
            "\x1BNb" => 'Ð', // 208 in CP1252
205
            "\x1BNDN" => 'Ñ', // 209 in CP1252
206
            "\x1BNAO" => 'Ò', // 210 in CP1252
207
            "\x1BNBO" => 'Ó', // 211 in CP1252
208
            "\x1BNCO" => 'Ô', // 212 in CP1252
209
            "\x1BNDO" => 'Õ', // 213 in CP1252
210
            "\x1BNHO" => 'Ö', // 214 in CP1252
211
            "\x1B-7" => '×', // 215 in CP1252
212
            "\x1BNi" => 'Ø', // 216 in CP1252
213
            "\x1BNAU" => 'Ù', // 217 in CP1252
214
            "\x1BNBU" => 'Ú', // 218 in CP1252
215
            "\x1BNCU" => 'Û', // 219 in CP1252
216
            "\x1BNHU" => 'Ü', // 220 in CP1252
217
            "\x1B-=" => 'Ý', // 221 in CP1252
218
            "\x1BNl" => 'Þ', // 222 in CP1252
219
            "\x1BN{" => 'ß', // 223 in CP1252
220
            "\x1BNAa" => 'à', // 224 in CP1252
221
            "\x1BNBa" => 'á', // 225 in CP1252
222
            "\x1BNCa" => 'â', // 226 in CP1252
223
            "\x1BNDa" => 'ã', // 227 in CP1252
224
            "\x1BNHa" => 'ä', // 228 in CP1252
225
            "\x1BNJa" => 'å', // 229 in CP1252
226
            "\x1BNq" => 'æ', // 230 in CP1252
227
            "\x1BNKc" => 'ç', // 231 in CP1252
228
            "\x1BNAe" => 'è', // 232 in CP1252
229
            "\x1BNBe" => 'é', // 233 in CP1252
230
            "\x1BNCe" => 'ê', // 234 in CP1252
231
            "\x1BNHe" => 'ë', // 235 in CP1252
232
            "\x1BNAi" => 'ì', // 236 in CP1252
233
            "\x1BNBi" => 'í', // 237 in CP1252
234
            "\x1BNCi" => 'î', // 238 in CP1252
235
            "\x1BNHi" => 'ï', // 239 in CP1252
236
            "\x1BNs" => 'ð', // 240 in CP1252
237
            "\x1BNDn" => 'ñ', // 241 in CP1252
238
            "\x1BNAo" => 'ò', // 242 in CP1252
239
            "\x1BNBo" => 'ó', // 243 in CP1252
240
            "\x1BNCo" => 'ô', // 244 in CP1252
241
            "\x1BNDo" => 'õ', // 245 in CP1252
242
            "\x1BNHo" => 'ö', // 246 in CP1252
243
            "\x1B/7" => '÷', // 247 in CP1252
244
            "\x1BNy" => 'ø', // 248 in CP1252
245
            "\x1BNAu" => 'ù', // 249 in CP1252
246
            "\x1BNBu" => 'ú', // 250 in CP1252
247
            "\x1BNCu" => 'û', // 251 in CP1252
248
            "\x1BNHu" => 'ü', // 252 in CP1252
249
            "\x1B/=" => 'ý', // 253 in CP1252
250
            "\x1BN|" => 'þ', // 254 in CP1252
251
            "\x1BNHy" => 'ÿ', // 255 in CP1252
252
        ];
253
    }
254
255
    /**
256
     * Get whether iconv extension is available.
257
     *
258
     * @return bool
259
     */
260 76
    public static function getIsIconvEnabled()
261
    {
262 76
        if (isset(self::$isIconvEnabled)) {
263 75
            return self::$isIconvEnabled;
264
        }
265
266
        // Fail if iconv doesn't exist
267 62
        if (!function_exists('iconv')) {
268
            self::$isIconvEnabled = false;
269
270
            return false;
271
        }
272
273
        // Sometimes iconv is not working, and e.g. iconv('UTF-8', 'UTF-16LE', 'x') just returns false,
274 62
        if (!@iconv('UTF-8', 'UTF-16LE', 'x')) {
275
            self::$isIconvEnabled = false;
276
277
            return false;
278
        }
279
280
        // Sometimes iconv_substr('A', 0, 1, 'UTF-8') just returns false in PHP 5.2.0
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
281
        // we cannot use iconv in that case either (http://bugs.php.net/bug.php?id=37773)
282 62
        if (!@iconv_substr('A', 0, 1, 'UTF-8')) {
283
            self::$isIconvEnabled = false;
284
285
            return false;
286
        }
287
288
        // CUSTOM: IBM AIX iconv() does not work
289 62
        if (defined('PHP_OS') && @stristr(PHP_OS, 'AIX') && defined('ICONV_IMPL') && (@strcasecmp(ICONV_IMPL, 'unknown') == 0) && defined('ICONV_VERSION') && (@strcasecmp(ICONV_VERSION, 'unknown') == 0)) {
290
            self::$isIconvEnabled = false;
291
292
            return false;
293
        }
294
295
        // If we reach here no problems were detected with iconv
296 62
        self::$isIconvEnabled = true;
297
298 62
        return true;
299
    }
300
301
    public static function buildCharacterSets()
302
    {
303
        if (empty(self::$controlCharacters)) {
304
            self::buildControlCharacters();
305
        }
306
        if (empty(self::$SYLKCharacters)) {
307
            self::buildSYLKCharacters();
308
        }
309
    }
310
311
    /**
312
     * Convert from OpenXML escaped control character to PHP control character.
313
     *
314
     * Excel 2007 team:
315
     * ----------------
316
     * That's correct, control characters are stored directly in the shared-strings table.
317
     * We do encode characters that cannot be represented in XML using the following escape sequence:
318
     * _xHHHH_ where H represents a hexadecimal character in the character's value...
319
     * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
320
     * element or in the shared string <t> element.
321
     *
322
     * @param string $value Value to unescape
323
     *
324
     * @return string
325
     */
326 8
    public static function controlCharacterOOXML2PHP($value = '')
327
    {
328 8
        return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
329
    }
330
331
    /**
332
     * Convert from PHP control character to OpenXML escaped control character.
333
     *
334
     * Excel 2007 team:
335
     * ----------------
336
     * That's correct, control characters are stored directly in the shared-strings table.
337
     * We do encode characters that cannot be represented in XML using the following escape sequence:
338
     * _xHHHH_ where H represents a hexadecimal character in the character's value...
339
     * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
340
     * element or in the shared string <t> element.
341
     *
342
     * @param string $value Value to escape
343
     *
344
     * @return string
345
     */
346 51
    public static function controlCharacterPHP2OOXML($value = '')
347
    {
348 51
        return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
349
    }
350
351
    /**
352
     * Try to sanitize UTF8, stripping invalid byte sequences. Not perfect. Does not surrogate characters.
353
     *
354
     * @param string $value
355
     *
356
     * @return string
357
     */
358 65
    public static function sanitizeUTF8($value)
359
    {
360 65
        if (self::getIsIconvEnabled()) {
361 65
            $value = @iconv('UTF-8', 'UTF-8', $value);
362
363 65
            return $value;
364
        }
365
366
        $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
367
368
        return $value;
369
    }
370
371
    /**
372
     * Check if a string contains UTF8 data.
373
     *
374
     * @param string $value
375
     *
376
     * @return bool
377
     */
378
    public static function isUTF8($value = '')
379
    {
380
        return $value === '' || preg_match('/^./su', $value) === 1;
381
    }
382
383
    /**
384
     * Formats a numeric value as a string for output in various output writers forcing
385
     * point as decimal separator in case locale is other than English.
386
     *
387
     * @param mixed $value
388
     *
389
     * @return string
390
     */
391 60
    public static function formatNumber($value)
392
    {
393 60
        if (is_float($value)) {
394 60
            return str_replace(',', '.', $value);
395
        }
396
397 56
        return (string) $value;
398
    }
399
400
    /**
401
     * Converts a UTF-8 string into BIFF8 Unicode string data (8-bit string length)
402
     * Writes the string using uncompressed notation, no rich text, no Asian phonetics
403
     * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
404
     * although this will give wrong results for non-ASCII strings
405
     * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3.
406
     *
407
     * @param string $value UTF-8 encoded string
408
     * @param mixed[] $arrcRuns Details of rich text runs in $value
409
     *
410
     * @return string
411
     */
412 38
    public static function UTF8toBIFF8UnicodeShort($value, $arrcRuns = [])
413
    {
414
        // character count
415 38
        $ln = self::countCharacters($value, 'UTF-8');
416
        // option flags
417 38
        if (empty($arrcRuns)) {
418 38
            $data = pack('CC', $ln, 0x0001);
419
            // characters
420 38
            $data .= self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
421
        } else {
422 9
            $data = pack('vC', $ln, 0x09);
423 9
            $data .= pack('v', count($arrcRuns));
424
            // characters
425 9
            $data .= self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
426 9
            foreach ($arrcRuns as $cRun) {
427 9
                $data .= pack('v', $cRun['strlen']);
428 9
                $data .= pack('v', $cRun['fontidx']);
429
            }
430
        }
431
432 38
        return $data;
433
    }
434
435
    /**
436
     * Converts a UTF-8 string into BIFF8 Unicode string data (16-bit string length)
437
     * Writes the string using uncompressed notation, no rich text, no Asian phonetics
438
     * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
439
     * although this will give wrong results for non-ASCII strings
440
     * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3.
441
     *
442
     * @param string $value UTF-8 encoded string
443
     *
444
     * @return string
445
     */
446 38
    public static function UTF8toBIFF8UnicodeLong($value)
447
    {
448
        // character count
449 38
        $ln = self::countCharacters($value, 'UTF-8');
450
451
        // characters
452 38
        $chars = self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
453
454 38
        $data = pack('vC', $ln, 0x0001) . $chars;
455
456 38
        return $data;
457
    }
458
459
    /**
460
     * Convert string from one encoding to another.
461
     *
462
     * @param string $value
463
     * @param string $to Encoding to convert to, e.g. 'UTF-8'
464
     * @param string $from Encoding to convert from, e.g. 'UTF-16LE'
465
     *
466
     * @return string
467
     */
468 38
    public static function convertEncoding($value, $to, $from)
469
    {
470 38
        if (self::getIsIconvEnabled()) {
471 38
            return iconv($from, $to . '//IGNORE//TRANSLIT', $value);
472
        }
473
474
        return mb_convert_encoding($value, $to, $from);
475
    }
476
477
    /**
478
     * Get character count.
479
     *
480
     * @param string $value
481
     * @param string $enc Encoding
482
     *
483
     * @return int Character count
484
     */
485 97
    public static function countCharacters($value, $enc = 'UTF-8')
486
    {
487 97
        return mb_strlen($value, $enc);
488
    }
489
490
    /**
491
     * Get a substring of a UTF-8 encoded string.
492
     *
493
     * @param string $pValue UTF-8 encoded string
494
     * @param int $pStart Start offset
495
     * @param int $pLength Maximum number of characters in substring
496
     *
497
     * @return string
498
     */
499 73
    public static function substring($pValue = '', $pStart = 0, $pLength = 0)
500
    {
501 73
        return mb_substr($pValue, $pStart, $pLength, 'UTF-8');
502
    }
503
504
    /**
505
     * Convert a UTF-8 encoded string to upper case.
506
     *
507
     * @param string $pValue UTF-8 encoded string
508
     *
509
     * @return string
510
     */
511 4
    public static function strToUpper($pValue = '')
512
    {
513 4
        return mb_convert_case($pValue, MB_CASE_UPPER, 'UTF-8');
514
    }
515
516
    /**
517
     * Convert a UTF-8 encoded string to lower case.
518
     *
519
     * @param string $pValue UTF-8 encoded string
520
     *
521
     * @return string
522
     */
523 4
    public static function strToLower($pValue = '')
524
    {
525 4
        return mb_convert_case($pValue, MB_CASE_LOWER, 'UTF-8');
526
    }
527
528
    /**
529
     * Convert a UTF-8 encoded string to title/proper case
530
     * (uppercase every first character in each word, lower case all other characters).
531
     *
532
     * @param string $pValue UTF-8 encoded string
533
     *
534
     * @return string
535
     */
536 3
    public static function strToTitle($pValue = '')
537
    {
538 3
        return mb_convert_case($pValue, MB_CASE_TITLE, 'UTF-8');
539
    }
540
541 21
    public static function mbIsUpper($char)
542
    {
543 21
        return mb_strtolower($char, 'UTF-8') != $char;
544
    }
545
546 21
    public static function mbStrSplit($string)
547
    {
548
        // Split at all position not after the start: ^
549
        // and not before the end: $
550 21
        return preg_split('/(?<!^)(?!$)/u', $string);
551
    }
552
553
    /**
554
     * Replace into multi-bytes string.
555
     *
556
     * Strangely, PHP doesn't have a mb_str_replace multibyte function
557
     * As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
558
     *
559
     * @param string|string[] $search
560
     * @param string|string[] $replace
561
     * @param string $subject
562
     *
563
     * @return string
564
     */
565 2
    public static function mbStrReplace($search, $replace, $subject)
566
    {
567 2
        if (is_array($subject)) {
568
            $ret = [];
569
            foreach ($subject as $key => $val) {
570
                $ret[$key] = self::mbStrReplace($search, $replace, $val);
571
            }
572
573
            return $ret;
574
        }
575
576 2
        foreach ((array) $search as $key => $s) {
577 2
            if ($s == '' && $s !== 0) {
578
                continue;
579
            }
580 2
            $r = !is_array($replace) ? $replace : (isset($replace[$key]) ? $replace[$key] : '');
581 2
            $pos = mb_strpos($subject, $s, 0, 'UTF-8');
582 2
            while ($pos !== false) {
583 2
                $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), null, 'UTF-8');
584 2
                $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
585
            }
586
        }
587
588 2
        return $subject;
589
    }
590
591
    /**
592
     * Reverse the case of a string, so that all uppercase characters become lowercase
593
     * and all lowercase characters become uppercase.
594
     *
595
     * @param string $pValue UTF-8 encoded string
596
     *
597
     * @return string
598
     */
599 21
    public static function strCaseReverse($pValue = '')
600
    {
601 21
        $characters = self::mbStrSplit($pValue);
602 21
        foreach ($characters as &$character) {
603 21
            if (self::mbIsUpper($character)) {
604 14
                $character = mb_strtolower($character, 'UTF-8');
605
            } else {
606 21
                $character = mb_strtoupper($character, 'UTF-8');
607
            }
608
        }
609
610 21
        return implode('', $characters);
611
    }
612
613
    /**
614
     * Identify whether a string contains a fractional numeric value,
615
     * and convert it to a numeric if it is.
616
     *
617
     * @param string &$operand string value to test
618
     *
619
     * @return bool
620
     */
621 1
    public static function convertToNumberIfFraction(&$operand)
622
    {
623 1
        if (preg_match('/^' . self::STRING_REGEXP_FRACTION . '$/i', $operand, $match)) {
624
            $sign = ($match[1] == '-') ? '-' : '+';
625
            $fractionFormula = '=' . $sign . $match[2] . $sign . $match[3];
626
            $operand = \PhpOffice\PhpSpreadsheet\Calculation::getInstance()->_calculateFormulaValue($fractionFormula);
627
628
            return true;
629
        }
630
631 1
        return false;
632
    }
633
634
    //    function convertToNumberIfFraction()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
635
636
    /**
637
     * Get the decimal separator. If it has not yet been set explicitly, try to obtain number
638
     * formatting information from locale.
639
     *
640
     * @return string
641
     */
642 31
    public static function getDecimalSeparator()
643
    {
644 31
        if (!isset(self::$decimalSeparator)) {
645 7
            $localeconv = localeconv();
646 7
            self::$decimalSeparator = ($localeconv['decimal_point'] != '')
647 7
                ? $localeconv['decimal_point'] : $localeconv['mon_decimal_point'];
648
649 7
            if (self::$decimalSeparator == '') {
650
                // Default to .
651
                self::$decimalSeparator = '.';
652
            }
653
        }
654
655 31
        return self::$decimalSeparator;
656
    }
657
658
    /**
659
     * Set the decimal separator. Only used by \PhpOffice\PhpSpreadsheet\Style\NumberFormat::toFormattedString()
660
     * to format output by \PhpOffice\PhpSpreadsheet\Writer\Html and \PhpOffice\PhpSpreadsheet\Writer\Pdf.
661
     *
662
     * @param string $pValue Character for decimal separator
663
     */
664 77
    public static function setDecimalSeparator($pValue = '.')
665
    {
666 77
        self::$decimalSeparator = $pValue;
667 77
    }
668
669
    /**
670
     * Get the thousands separator. If it has not yet been set explicitly, try to obtain number
671
     * formatting information from locale.
672
     *
673
     * @return string
674
     */
675 39
    public static function getThousandsSeparator()
676
    {
677 39
        if (!isset(self::$thousandsSeparator)) {
678 7
            $localeconv = localeconv();
679 7
            self::$thousandsSeparator = ($localeconv['thousands_sep'] != '')
680 7
                ? $localeconv['thousands_sep'] : $localeconv['mon_thousands_sep'];
681
682 7
            if (self::$thousandsSeparator == '') {
683
                // Default to .
684
                self::$thousandsSeparator = ',';
685
            }
686
        }
687
688 39
        return self::$thousandsSeparator;
689
    }
690
691
    /**
692
     * Set the thousands separator. Only used by \PhpOffice\PhpSpreadsheet\Style\NumberFormat::toFormattedString()
693
     * to format output by \PhpOffice\PhpSpreadsheet\Writer\Html and \PhpOffice\PhpSpreadsheet\Writer\Pdf.
694
     *
695
     * @param string $pValue Character for thousands separator
696
     */
697 77
    public static function setThousandsSeparator($pValue = ',')
698
    {
699 77
        self::$thousandsSeparator = $pValue;
700 77
    }
701
702
    /**
703
     *    Get the currency code. If it has not yet been set explicitly, try to obtain the
704
     *        symbol information from locale.
705
     *
706
     * @return string
707
     */
708 18
    public static function getCurrencyCode()
709
    {
710 18
        if (!empty(self::$currencyCode)) {
711 17
            return self::$currencyCode;
712
        }
713 2
        self::$currencyCode = '$';
714 2
        $localeconv = localeconv();
715 2
        if (!empty($localeconv['currency_symbol'])) {
716 2
            self::$currencyCode = $localeconv['currency_symbol'];
717
718 2
            return self::$currencyCode;
719
        }
720
        if (!empty($localeconv['int_curr_symbol'])) {
721
            self::$currencyCode = $localeconv['int_curr_symbol'];
722
723
            return self::$currencyCode;
724
        }
725
726
        return self::$currencyCode;
727
    }
728
729
    /**
730
     * Set the currency code. Only used by \PhpOffice\PhpSpreadsheet\Style\NumberFormat::toFormattedString()
731
     *        to format output by \PhpOffice\PhpSpreadsheet\Writer\Html and \PhpOffice\PhpSpreadsheet\Writer\Pdf.
732
     *
733
     * @param string $pValue Character for currency code
734
     */
735 38
    public static function setCurrencyCode($pValue = '$')
736
    {
737 38
        self::$currencyCode = $pValue;
738 38
    }
739
740
    /**
741
     * Convert SYLK encoded string to UTF-8.
742
     *
743
     * @param string $pValue
744
     *
745
     * @return string UTF-8 encoded string
746
     */
747 1
    public static function SYLKtoUTF8($pValue = '')
748
    {
749
        // If there is no escape character in the string there is nothing to do
750 1
        if (strpos($pValue, '') === false) {
751 1
            return $pValue;
752
        }
753
754
        foreach (self::$SYLKCharacters as $k => $v) {
755
            $pValue = str_replace($k, $v, $pValue);
756
        }
757
758
        return $pValue;
759
    }
760
761
    /**
762
     * Retrieve any leading numeric part of a string, or return the full string if no leading numeric
763
     * (handles basic integer or float, but not exponent or non decimal).
764
     *
765
     * @param string $value
766
     *
767
     * @return mixed string or only the leading numeric part of the string
768
     */
769 83
    public static function testStringAsNumeric($value)
770
    {
771 83
        if (is_numeric($value)) {
772 83
            return $value;
773
        }
774 3
        $v = (float) $value;
775
776 3
        return (is_numeric(substr($value, 0, strlen($v)))) ? $v : $value;
777
    }
778
}
779