diff --git a/CHANGELOG.md b/CHANGELOG.md index 7941c99247..35be7d1298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Treat strings containing percentage values as floats in Calculation Engine operations [Issue #3155](https://github.com/PHPOffice/PhpSpreadsheet/issues/3155) [PR #3156](https://github.com/PHPOffice/PhpSpreadsheet/pull/3156) and [PR #3164](https://github.com/PHPOffice/PhpSpreadsheet/pull/3164) - Xlsx Reader Accept Palette of Fewer than 64 Colors [Issue #3093](https://github.com/PHPOffice/PhpSpreadsheet/issues/3093) [PR #3096](https://github.com/PHPOffice/PhpSpreadsheet/pull/3096) - Use Locale-Independent Float Conversion for Xlsx Writer Custom Property [Issue #3095](https://github.com/PHPOffice/PhpSpreadsheet/issues/3095) [PR #3099](https://github.com/PHPOffice/PhpSpreadsheet/pull/3099) - Allow setting AutoFilter range on a single cell or row [Issue #3102](https://github.com/PHPOffice/PhpSpreadsheet/issues/3102) [PR #3111](https://github.com/PHPOffice/PhpSpreadsheet/pull/3111) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index a597bc64c2..8aaa2e7098 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -5110,7 +5110,7 @@ private function validateBinaryOperand(&$operand, &$stack) $this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($operand)); return false; - } elseif (!Shared\StringHelper::convertToNumberIfFraction($operand) && !Shared\StringHelper::convertToNumberIfPercent($operand)) { + } elseif (Engine\FormattedNumber::convertToNumberIfFormatted($operand) === false) { // If not a numeric, a fraction or a percentage, then it's a text string, and so can't be used in mathematical binary operations $stack->push('Error', '#VALUE!'); $this->debugLog->writeDebugLog('Evaluation Result is a %s', $this->showTypeDetails('#VALUE!')); @@ -5120,7 +5120,7 @@ private function validateBinaryOperand(&$operand, &$stack) } } - // return a true if the value of the operand is one that we can use in normal binary operations + // return a true if the value of the operand is one that we can use in normal binary mathematical operations return true; } diff --git a/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php new file mode 100644 index 0000000000..70a2317195 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php @@ -0,0 +1,95 @@ +[-+])? *\% *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *\% *))$~i'; + + private const STRING_CONVERSION_LIST = [ + [self::class, 'convertToNumberIfNumeric'], + [self::class, 'convertToNumberIfFraction'], + [self::class, 'convertToNumberIfPercent'], + ]; + + /** + * Identify whether a string contains a formatted numeric value, + * and convert it to a numeric if it is. + * + * @param string $operand string value to test + */ + public static function convertToNumberIfFormatted(string &$operand): bool + { + foreach (self::STRING_CONVERSION_LIST as $conversionMethod) { + if ($conversionMethod($operand) === true) { + return true; + } + } + + return false; + } + + /** + * Identify whether a string contains a numeric value, + * and convert it to a numeric if it is. + * + * @param string $operand string value to test + */ + public static function convertToNumberIfNumeric(string &$operand): bool + { + if (is_numeric($operand)) { + $operand = (float) $operand; + + return true; + } + + return false; + } + + /** + * Identify whether a string contains a fractional numeric value, + * and convert it to a numeric if it is. + * + * @param string $operand string value to test + */ + public static function convertToNumberIfFraction(string &$operand): bool + { + if (preg_match(self::STRING_REGEXP_FRACTION, $operand, $match)) { + $sign = ($match[1] === '-') ? '-' : '+'; + $wholePart = ($match[3] === '') ? '' : ($sign . $match[3]); + $fractionFormula = '=' . $wholePart . $sign . $match[4]; + $operand = Calculation::getInstance()->_calculateFormulaValue($fractionFormula); + + return true; + } + + return false; + } + + /** + * Identify whether a string contains a percentage, and if so, + * convert it to a numeric. + * + * @param string $operand string value to test + */ + public static function convertToNumberIfPercent(string &$operand): bool + { + $match = []; + if (preg_match(self::STRING_REGEXP_PERCENT, $operand, $match, PREG_UNMATCHED_AS_NULL)) { + //Calculate the percentage + $sign = ($match['PrefixedSign'] ?? $match['PrefixedSign2'] ?? $match['PostfixedSign']) ?? ''; + $operand = (float) ($sign . ($match['PostfixedValue'] ?? $match['PrefixedValue'])) / 100; + + return true; + } + + return false; + } +} diff --git a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php index 5e35d49195..1d93394b1e 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php +++ b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php @@ -2,10 +2,10 @@ namespace PhpOffice\PhpSpreadsheet\Shared\JAMA; +use PhpOffice\PhpSpreadsheet\Calculation\Engine\FormattedNumber; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; -use PhpOffice\PhpSpreadsheet\Shared\StringHelper; /** * Matrix class. @@ -1169,7 +1169,7 @@ private function validateExtractedValue($value, bool $validValues): array } if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) { $value = trim($value, '"'); - $validValues &= StringHelper::convertToNumberIfFraction($value); + $validValues &= FormattedNumber::convertToNumberIfFormatted($value); } return [$value, $validValues]; diff --git a/src/PhpSpreadsheet/Shared/StringHelper.php b/src/PhpSpreadsheet/Shared/StringHelper.php index 06edf07221..30bd8c5fd0 100644 --- a/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/src/PhpSpreadsheet/Shared/StringHelper.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Shared; -use PhpOffice\PhpSpreadsheet\Calculation\Calculation; - class StringHelper { - /** Constants */ - /** Regular Expressions */ - // Fraction - const STRING_REGEXP_FRACTION = '~^\s*(-?)((\d*)\s+)?(\d+\/\d+)\s*$~'; - - const STRING_REGEXP_PERCENT = '~^(?:(?: *(?[-+])? *\% *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *\% *))$~i'; - /** * Control characters array. * @@ -540,46 +531,6 @@ public static function strCaseReverse(string $textValue): string return implode('', $characters); } - /** - * Identify whether a string contains a fractional numeric value, - * and convert it to a numeric if it is. - * - * @param string $operand string value to test - */ - public static function convertToNumberIfFraction(string &$operand): bool - { - if (preg_match(self::STRING_REGEXP_FRACTION, $operand, $match)) { - $sign = ($match[1] == '-') ? '-' : '+'; - $wholePart = ($match[3] === '') ? '' : ($sign . $match[3]); - $fractionFormula = '=' . $wholePart . $sign . $match[4]; - $operand = Calculation::getInstance()->_calculateFormulaValue($fractionFormula); - - return true; - } - - return false; - } - - /** - * Identify whether a string contains a percentage, and if so, - * convert it to a numeric. - * - * @param string $operand string value to test - */ - public static function convertToNumberIfPercent(string &$operand): bool - { - $match = []; - if (preg_match(self::STRING_REGEXP_PERCENT, $operand, $match, PREG_UNMATCHED_AS_NULL)) { - //Calculate the percentage - $sign = ($match['PrefixedSign'] ?? $match['PrefixedSign2'] ?? $match['PostfixedSign']) ?? ''; - $operand = (float) ($sign . ($match['PostfixedValue'] ?? $match['PrefixedValue'])) / 100; - - return true; - } - - return false; - } - /** * Get the decimal separator. If it has not yet been set explicitly, try to obtain number * formatting information from locale. diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index 0d730073e2..0b94c19ecd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -180,6 +180,30 @@ public function testCellWithFormulaTwoIndirect(): void self::assertEquals('9', $cell3->getCalculatedValue()); } + public function testCellWithStringNumeric(): void + { + $spreadsheet = new Spreadsheet(); + $workSheet = $spreadsheet->getActiveSheet(); + $cell1 = $workSheet->getCell('A1'); + $cell1->setValue('+2.5'); + $cell2 = $workSheet->getCell('B1'); + $cell2->setValue('=100*A1'); + + self::assertSame(250.0, $cell2->getCalculatedValue()); + } + + public function testCellWithStringFraction(): void + { + $spreadsheet = new Spreadsheet(); + $workSheet = $spreadsheet->getActiveSheet(); + $cell1 = $workSheet->getCell('A1'); + $cell1->setValue('3/4'); + $cell2 = $workSheet->getCell('B1'); + $cell2->setValue('=100*A1'); + + self::assertSame(75.0, $cell2->getCalculatedValue()); + } + public function testCellWithStringPercentage(): void { $spreadsheet = new Spreadsheet(); @@ -189,7 +213,7 @@ public function testCellWithStringPercentage(): void $cell2 = $workSheet->getCell('B1'); $cell2->setValue('=100*A1'); - self::assertEquals('2', $cell2->getCalculatedValue()); + self::assertSame(2.0, $cell2->getCalculatedValue()); } public function testBranchPruningFormulaParsingSimpleCase(): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php new file mode 100644 index 0000000000..40c16cecbe --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php @@ -0,0 +1,186 @@ + ['1', '1'], + 'common fraction' => ['1.5', '1 1/2'], + 'fraction between -1 and 0' => ['-0.5', '-1/2'], + 'fraction between -1 and 0 with space' => ['-0.5', ' - 1/2'], + 'fraction between 0 and 1' => ['0.75', '3/4 '], + 'fraction between 0 and 1 with space' => ['0.75', ' 3/4'], + 'improper fraction' => ['1.75', '7/4'], + ]; + } + + /** + * @dataProvider providerPercentages + */ + public function testPercentage(string $expected, string $value): void + { + $originalValue = $value; + $result = FormattedNumber::convertToNumberIfPercent($value); + if ($result === false) { + self::assertSame($expected, $originalValue); + self::assertSame($expected, $value); + } else { + self::assertSame($expected, (string) $value); + self::assertNotEquals($value, $originalValue); + } + } + + public function providerPercentages(): array + { + return [ + 'non-percentage' => ['10', '10'], + 'single digit percentage' => ['0.02', '2%'], + 'two digit percentage' => ['0.13', '13%'], + 'negative single digit percentage' => ['-0.07', '-7%'], + 'negative two digit percentage' => ['-0.75', '-75%'], + 'large percentage' => ['98.45', '9845%'], + 'small percentage' => ['0.0005', '0.05%'], + 'percentage with decimals' => ['0.025', '2.5%'], + 'trailing percent with space' => ['0.02', '2 %'], + 'trailing percent with leading and trailing space' => ['0.02', ' 2 % '], + 'leading percent with decimals' => ['0.025', ' % 2.5'], + + //These should all fail + 'percent only' => ['%', '%'], + 'nonsense percent' => ['2%2', '2%2'], + 'negative leading percent' => ['-0.02', '-%2'], + + //Percent position permutations + 'permutation_1' => ['0.02', '2%'], + 'permutation_2' => ['0.02', ' 2%'], + 'permutation_3' => ['0.02', '2% '], + 'permutation_4' => ['0.02', ' 2 % '], + 'permutation_5' => ['0.0275', '2.75% '], + 'permutation_6' => ['0.0275', ' 2.75% '], + 'permutation_7' => ['0.0275', ' 2.75 % '], + 'permutation_8' => [' 2 . 75 %', ' 2 . 75 %'], + 'permutation_9' => [' 2.7 5 % ', ' 2.7 5 % '], + 'permutation_10' => ['-0.02', '-2%'], + 'permutation_11' => ['-0.02', ' -2% '], + 'permutation_12' => ['-0.02', '- 2% '], + 'permutation_13' => ['-0.02', '-2 % '], + 'permutation_14' => ['-0.0275', '-2.75% '], + 'permutation_15' => ['-0.0275', ' -2.75% '], + 'permutation_16' => ['-0.0275', '-2.75 % '], + 'permutation_17' => ['-0.0275', ' - 2.75 % '], + 'permutation_18' => ['0.02', '2%'], + 'permutation_19' => ['0.02', '% 2 '], + 'permutation_20' => ['0.02', ' %2 '], + 'permutation_21' => ['0.02', ' % 2 '], + 'permutation_22' => ['0.0275', '%2.75 '], + 'permutation_23' => ['0.0275', ' %2.75 '], + 'permutation_24' => ['0.0275', ' % 2.75 '], + 'permutation_25' => [' %2 . 75 ', ' %2 . 75 '], + 'permutation_26' => [' %2.7 5 ', ' %2.7 5 '], + 'permutation_27' => [' % 2 . 75 ', ' % 2 . 75 '], + 'permutation_28' => [' % 2.7 5 ', ' % 2.7 5 '], + 'permutation_29' => ['-0.0275', '-%2.75 '], + 'permutation_30' => ['-0.0275', ' - %2.75 '], + 'permutation_31' => ['-0.0275', '- % 2.75 '], + 'permutation_32' => ['-0.0275', ' - % 2.75 '], + 'permutation_33' => ['0.02', '2%'], + 'permutation_34' => ['0.02', '2 %'], + 'permutation_35' => ['0.02', ' 2%'], + 'permutation_36' => ['0.02', ' 2 % '], + 'permutation_37' => ['0.0275', '2.75%'], + 'permutation_38' => ['0.0275', ' 2.75 % '], + 'permutation_39' => ['2 . 75 % ', '2 . 75 % '], + 'permutation_40' => ['-0.0275', '-2.75% '], + 'permutation_41' => ['-0.0275', '- 2.75% '], + 'permutation_42' => ['-0.0275', ' - 2.75% '], + 'permutation_43' => ['-0.0275', ' -2.75 % '], + 'permutation_44' => ['-2. 75 % ', '-2. 75 % '], + 'permutation_45' => ['%', '%'], + 'permutation_46' => ['0.02', '%2 '], + 'permutation_47' => ['0.02', '% 2 '], + 'permutation_48' => ['0.02', ' %2 '], + 'permutation_49' => ['0.02', '% 2 '], + 'permutation_50' => ['0.02', ' % 2 '], + 'permutation_51' => ['0.02', ' 2 % '], + 'permutation_52' => ['-0.02', '-2%'], + 'permutation_53' => ['-0.02', '- %2'], + 'permutation_54' => ['-0.02', ' -%2 '], + 'permutation_55' => ['2%2', '2%2'], + 'permutation_56' => [' 2% %', ' 2% %'], + 'permutation_57' => [' % 2 -', ' % 2 -'], + 'permutation_58' => ['-0.02', '%-2'], + 'permutation_59' => ['-0.02', ' % - 2'], + 'permutation_60' => ['-0.0275', '%-2.75 '], + 'permutation_61' => ['-0.0275', ' % - 2.75 '], + 'permutation_62' => ['-0.0275', ' % - 2.75 '], + 'permutation_63' => ['-0.0275', ' % - 2.75 '], + 'permutation_64' => ['0.0275', ' % + 2.75 '], + 'permutation_65' => ['0.0275', ' % + 2.75 '], + 'permutation_66' => ['0.0275', ' % + 2.75 '], + 'permutation_67' => ['0.02', '+2%'], + 'permutation_68' => ['0.02', ' +2% '], + 'permutation_69' => ['0.02', '+ 2% '], + 'permutation_70' => ['0.02', '+2 % '], + 'permutation_71' => ['0.0275', '+2.75% '], + 'permutation_72' => ['0.0275', ' +2.75% '], + 'permutation_73' => ['0.0275', '+2.75 % '], + 'permutation_74' => ['0.0275', ' + 2.75 % '], + 'permutation_75' => ['-2.5E-6', '-2.5E-4%'], + 'permutation_76' => ['200', '2E4%'], + 'permutation_77' => ['-2.5E-8', '-%2.50E-06'], + 'permutation_78' => [' - % 2.50 E -06 ', ' - % 2.50 E -06 '], + 'permutation_79' => ['-2.5E-8', ' - % 2.50E-06 '], + 'permutation_80' => [' - % 2.50E- 06 ', ' - % 2.50E- 06 '], + 'permutation_81' => [' - % 2.50E - 06 ', ' - % 2.50E - 06 '], + 'permutation_82' => ['-2.5E-6', '-2.5e-4%'], + 'permutation_83' => ['200', '2e4%'], + 'permutation_84' => ['-2.5E-8', '-%2.50e-06'], + 'permutation_85' => [' - % 2.50 e -06 ', ' - % 2.50 e -06 '], + 'permutation_86' => ['-2.5E-8', ' - % 2.50e-06 '], + 'permutation_87' => [' - % 2.50e- 06 ', ' - % 2.50e- 06 '], + 'permutation_88' => [' - % 2.50e - 06 ', ' - % 2.50e - 06 '], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php b/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php index 34bde28824..bcbcd5d215 100644 --- a/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php +++ b/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php @@ -119,161 +119,4 @@ public function testSYLKtoUTF8(): void self::assertEquals($expectedResult, $result); } - - /** - * @dataProvider providerFractions - */ - public function testFraction(string $expected, string $value): void - { - $originalValue = $value; - $result = StringHelper::convertToNumberIfFraction($value); - if ($result === false) { - self::assertSame($expected, $originalValue); - self::assertSame($expected, $value); - } else { - self::assertSame($expected, (string) $value); - self::assertNotEquals($value, $originalValue); - } - } - - public function providerFractions(): array - { - return [ - 'non-fraction' => ['1', '1'], - 'common fraction' => ['1.5', '1 1/2'], - 'fraction between -1 and 0' => ['-0.5', '-1/2'], - 'fraction between -1 and 0 with space' => ['-0.5', ' - 1/2'], - 'fraction between 0 and 1' => ['0.75', '3/4 '], - 'fraction between 0 and 1 with space' => ['0.75', ' 3/4'], - 'improper fraction' => ['1.75', '7/4'], - ]; - } - - /** - * @dataProvider providerPercentages - */ - public function testPercentage(string $expected, string $value): void - { - $originalValue = $value; - $result = StringHelper::convertToNumberIfPercent($value); - if ($result === false) { - self::assertSame($expected, $originalValue); - self::assertSame($expected, $value); - } else { - self::assertSame($expected, (string) $value); - self::assertNotEquals($value, $originalValue); - } - } - - public function providerPercentages(): array - { - return [ - 'non-percentage' => ['10', '10'], - 'single digit percentage' => ['0.02', '2%'], - 'two digit percentage' => ['0.13', '13%'], - 'negative single digit percentage' => ['-0.07', '-7%'], - 'negative two digit percentage' => ['-0.75', '-75%'], - 'large percentage' => ['98.45', '9845%'], - 'small percentage' => ['0.0005', '0.05%'], - 'percentage with decimals' => ['0.025', '2.5%'], - 'trailing percent with space' => ['0.02', '2 %'], - 'trailing percent with leading and trailing space' => ['0.02', ' 2 % '], - 'leading percent with decimals' => ['0.025', ' % 2.5'], - - //These should all fail - 'percent only' => ['%', '%'], - 'nonsense percent' => ['2%2', '2%2'], - 'negative leading percent' => ['-0.02', '-%2'], - - //Percent position permutations - 'permutation_1' => ['0.02', '2%'], - 'permutation_2' => ['0.02', ' 2%'], - 'permutation_3' => ['0.02', '2% '], - 'permutation_4' => ['0.02', ' 2 % '], - 'permutation_5' => ['0.0275', '2.75% '], - 'permutation_6' => ['0.0275', ' 2.75% '], - 'permutation_7' => ['0.0275', ' 2.75 % '], - 'permutation_8' => [' 2 . 75 %', ' 2 . 75 %'], - 'permutation_9' => [' 2.7 5 % ', ' 2.7 5 % '], - 'permutation_10' => ['-0.02', '-2%'], - 'permutation_11' => ['-0.02', ' -2% '], - 'permutation_12' => ['-0.02', '- 2% '], - 'permutation_13' => ['-0.02', '-2 % '], - 'permutation_14' => ['-0.0275', '-2.75% '], - 'permutation_15' => ['-0.0275', ' -2.75% '], - 'permutation_16' => ['-0.0275', '-2.75 % '], - 'permutation_17' => ['-0.0275', ' - 2.75 % '], - 'permutation_18' => ['0.02', '2%'], - 'permutation_19' => ['0.02', '% 2 '], - 'permutation_20' => ['0.02', ' %2 '], - 'permutation_21' => ['0.02', ' % 2 '], - 'permutation_22' => ['0.0275', '%2.75 '], - 'permutation_23' => ['0.0275', ' %2.75 '], - 'permutation_24' => ['0.0275', ' % 2.75 '], - 'permutation_25' => [' %2 . 75 ', ' %2 . 75 '], - 'permutation_26' => [' %2.7 5 ', ' %2.7 5 '], - 'permutation_27' => [' % 2 . 75 ', ' % 2 . 75 '], - 'permutation_28' => [' % 2.7 5 ', ' % 2.7 5 '], - 'permutation_29' => ['-0.0275', '-%2.75 '], - 'permutation_30' => ['-0.0275', ' - %2.75 '], - 'permutation_31' => ['-0.0275', '- % 2.75 '], - 'permutation_32' => ['-0.0275', ' - % 2.75 '], - 'permutation_33' => ['0.02', '2%'], - 'permutation_34' => ['0.02', '2 %'], - 'permutation_35' => ['0.02', ' 2%'], - 'permutation_36' => ['0.02', ' 2 % '], - 'permutation_37' => ['0.0275', '2.75%'], - 'permutation_38' => ['0.0275', ' 2.75 % '], - 'permutation_39' => ['2 . 75 % ', '2 . 75 % '], - 'permutation_40' => ['-0.0275', '-2.75% '], - 'permutation_41' => ['-0.0275', '- 2.75% '], - 'permutation_42' => ['-0.0275', ' - 2.75% '], - 'permutation_43' => ['-0.0275', ' -2.75 % '], - 'permutation_44' => ['-2. 75 % ', '-2. 75 % '], - 'permutation_45' => ['%', '%'], - 'permutation_46' => ['0.02', '%2 '], - 'permutation_47' => ['0.02', '% 2 '], - 'permutation_48' => ['0.02', ' %2 '], - 'permutation_49' => ['0.02', '% 2 '], - 'permutation_50' => ['0.02', ' % 2 '], - 'permutation_51' => ['0.02', ' 2 % '], - 'permutation_52' => ['-0.02', '-2%'], - 'permutation_53' => ['-0.02', '- %2'], - 'permutation_54' => ['-0.02', ' -%2 '], - 'permutation_55' => ['2%2', '2%2'], - 'permutation_56' => [' 2% %', ' 2% %'], - 'permutation_57' => [' % 2 -', ' % 2 -'], - 'permutation_58' => ['-0.02', '%-2'], - 'permutation_59' => ['-0.02', ' % - 2'], - 'permutation_60' => ['-0.0275', '%-2.75 '], - 'permutation_61' => ['-0.0275', ' % - 2.75 '], - 'permutation_62' => ['-0.0275', ' % - 2.75 '], - 'permutation_63' => ['-0.0275', ' % - 2.75 '], - 'permutation_64' => ['0.0275', ' % + 2.75 '], - 'permutation_65' => ['0.0275', ' % + 2.75 '], - 'permutation_66' => ['0.0275', ' % + 2.75 '], - 'permutation_67' => ['0.02', '+2%'], - 'permutation_68' => ['0.02', ' +2% '], - 'permutation_69' => ['0.02', '+ 2% '], - 'permutation_70' => ['0.02', '+2 % '], - 'permutation_71' => ['0.0275', '+2.75% '], - 'permutation_72' => ['0.0275', ' +2.75% '], - 'permutation_73' => ['0.0275', '+2.75 % '], - 'permutation_74' => ['0.0275', ' + 2.75 % '], - 'permutation_75' => ['-2.5E-6', '-2.5E-4%'], - 'permutation_76' => ['200', '2E4%'], - 'permutation_77' => ['-2.5E-8', '-%2.50E-06'], - 'permutation_78' => [' - % 2.50 E -06 ', ' - % 2.50 E -06 '], - 'permutation_79' => ['-2.5E-8', ' - % 2.50E-06 '], - 'permutation_80' => [' - % 2.50E- 06 ', ' - % 2.50E- 06 '], - 'permutation_81' => [' - % 2.50E - 06 ', ' - % 2.50E - 06 '], - 'permutation_82' => ['-2.5E-6', '-2.5e-4%'], - 'permutation_83' => ['200', '2e4%'], - 'permutation_84' => ['-2.5E-8', '-%2.50e-06'], - 'permutation_85' => [' - % 2.50 e -06 ', ' - % 2.50 e -06 '], - 'permutation_86' => ['-2.5E-8', ' - % 2.50e-06 '], - 'permutation_87' => [' - % 2.50e- 06 ', ' - % 2.50e- 06 '], - 'permutation_88' => [' - % 2.50e - 06 ', ' - % 2.50e - 06 '], - ]; - } }