Comparison operators on strings are usually case insensitive
Excel, Gnumeric and Google Spreadsheet are case insensitive, so the default behavior of PHPExcel is modified accordingly. However OpenOffice is case sensitive and is also supported via the compatibility mode of PHPExcel. Fixes #31
This commit is contained in:
parent
f5bd6dc0f2
commit
f2e24ecdd4
|
@ -3557,15 +3557,37 @@ class PHPExcel_Calculation {
|
||||||
if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') { $operand1 = self::_unwrapResult($operand1); }
|
if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') { $operand1 = self::_unwrapResult($operand1); }
|
||||||
if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') { $operand2 = self::_unwrapResult($operand2); }
|
if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') { $operand2 = self::_unwrapResult($operand2); }
|
||||||
|
|
||||||
|
// Use case insensitive comparaison if not OpenOffice mode
|
||||||
|
if (PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE)
|
||||||
|
{
|
||||||
|
if (is_string($operand1)) {
|
||||||
|
$operand1 = strtoupper($operand1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($operand2)) {
|
||||||
|
$operand2 = strtoupper($operand2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$useLowercaseFirstComparison = is_string($operand1) && is_string($operand2) && PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE;
|
||||||
|
|
||||||
// execute the necessary operation
|
// execute the necessary operation
|
||||||
switch ($operation) {
|
switch ($operation) {
|
||||||
// Greater than
|
// Greater than
|
||||||
case '>':
|
case '>':
|
||||||
$result = ($operand1 > $operand2);
|
if ($useLowercaseFirstComparison) {
|
||||||
|
$result = $this->strcmpLowercaseFirst($operand1, $operand2) > 0;
|
||||||
|
} else {
|
||||||
|
$result = ($operand1 > $operand2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// Less than
|
// Less than
|
||||||
case '<':
|
case '<':
|
||||||
$result = ($operand1 < $operand2);
|
if ($useLowercaseFirstComparison) {
|
||||||
|
$result = $this->strcmpLowercaseFirst($operand1, $operand2) < 0;
|
||||||
|
} else {
|
||||||
|
$result = ($operand1 < $operand2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// Equality
|
// Equality
|
||||||
case '=':
|
case '=':
|
||||||
|
@ -3573,11 +3595,19 @@ class PHPExcel_Calculation {
|
||||||
break;
|
break;
|
||||||
// Greater than or equal
|
// Greater than or equal
|
||||||
case '>=':
|
case '>=':
|
||||||
$result = ($operand1 >= $operand2);
|
if ($useLowercaseFirstComparison) {
|
||||||
|
$result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0;
|
||||||
|
} else {
|
||||||
|
$result = ($operand1 >= $operand2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// Less than or equal
|
// Less than or equal
|
||||||
case '<=':
|
case '<=':
|
||||||
$result = ($operand1 <= $operand2);
|
if ($useLowercaseFirstComparison) {
|
||||||
|
$result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0;
|
||||||
|
} else {
|
||||||
|
$result = ($operand1 <= $operand2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// Inequality
|
// Inequality
|
||||||
case '<>':
|
case '<>':
|
||||||
|
@ -3592,6 +3622,21 @@ class PHPExcel_Calculation {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} // function _executeBinaryComparisonOperation()
|
} // function _executeBinaryComparisonOperation()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters
|
||||||
|
* @param string $str1
|
||||||
|
* @param string $str2
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
private function strcmpLowercaseFirst($str1, $str2)
|
||||||
|
{
|
||||||
|
$from = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||||
|
$to = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
$inversedStr1 = strtr($str1, $from, $to);
|
||||||
|
$inversedStr2 = strtr($str2, $from, $to);
|
||||||
|
|
||||||
|
return strcmp($inversedStr1, $inversedStr2);
|
||||||
|
}
|
||||||
|
|
||||||
private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) {
|
private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) {
|
||||||
// Validate the two operands
|
// Validate the two operands
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'testDataFileIterator.php';
|
||||||
|
|
||||||
|
class CalculationTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
if (!defined('PHPEXCEL_ROOT')) {
|
||||||
|
define('PHPEXCEL_ROOT', APPLICATION_PATH . '/');
|
||||||
|
}
|
||||||
|
require_once(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerBinaryComparisonOperation
|
||||||
|
*/
|
||||||
|
public function testBinaryComparisonOperation($formula, $expectedResultExcel, $expectedResultOpenOffice)
|
||||||
|
{
|
||||||
|
PHPExcel_Calculation_Functions::setCompatibilityMode(PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL);
|
||||||
|
$resultExcel = \PHPExcel_Calculation::getInstance()->_calculateFormulaValue($formula);
|
||||||
|
$this->assertEquals($expectedResultExcel, $resultExcel, 'should be Excel compatible');
|
||||||
|
|
||||||
|
PHPExcel_Calculation_Functions::setCompatibilityMode(PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE);
|
||||||
|
$resultOpenOffice = \PHPExcel_Calculation::getInstance()->_calculateFormulaValue($formula);
|
||||||
|
$this->assertEquals($expectedResultOpenOffice, $resultOpenOffice, 'should be OpenOffice compatible');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerBinaryComparisonOperation()
|
||||||
|
{
|
||||||
|
return new testDataFileIterator('rawTestData/CalculationBinaryComparisonOperation.data');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
# formula, expectedResultExcel, expectedResultOpenOffice
|
||||||
|
'=TRUE', TRUE, TRUE
|
||||||
|
'=1 + 2.5', 3.5, 3.5
|
||||||
|
'=2.5 + 1', 3.5, 3.5
|
||||||
|
'=1 - 2.5', -1.5, -1.5
|
||||||
|
'=2.5 - 1', 1.5, 1.5
|
||||||
|
'=3 > 1', TRUE, TRUE
|
||||||
|
'=3 > 3', FALSE, FALSE
|
||||||
|
'=1 > 3', FALSE, FALSE
|
||||||
|
'=3 < 1', FALSE, FALSE
|
||||||
|
'=3 < 3', FALSE, FALSE
|
||||||
|
'=1 < 3', TRUE, TRUE
|
||||||
|
'=3 = 1', FALSE, FALSE
|
||||||
|
'=3 = 3', TRUE, TRUE
|
||||||
|
'=1 = 1.0', TRUE, TRUE
|
||||||
|
'=3 >= 1', TRUE, TRUE
|
||||||
|
'=3 >= 3', TRUE, TRUE
|
||||||
|
'=1 >= 3', FALSE, FALSE
|
||||||
|
'=3 <= 1', FALSE, FALSE
|
||||||
|
'=3 <= 3', TRUE, TRUE
|
||||||
|
'=1 <= 3', TRUE, TRUE
|
||||||
|
'=3 <> 1', TRUE, TRUE
|
||||||
|
'=3 <> 3', FALSE, FALSE
|
||||||
|
'=1 <> 1.0', FALSE, FALSE
|
||||||
|
'="a" > "a"', FALSE, FALSE
|
||||||
|
'="A" > "A"', FALSE, FALSE
|
||||||
|
'="A" > "a"', FALSE, TRUE
|
||||||
|
'="a" > "A"', FALSE, FALSE
|
||||||
|
'="a" < "a"', FALSE, FALSE
|
||||||
|
'="A" < "A"', FALSE, FALSE
|
||||||
|
'="A" < "a"', FALSE, FALSE
|
||||||
|
'="a" < "A"', FALSE, TRUE
|
||||||
|
'="a" = "a"', TRUE, TRUE
|
||||||
|
'="A" = "A"', TRUE, TRUE
|
||||||
|
'="A" = "a"', TRUE, FALSE
|
||||||
|
'="a" = "A"', TRUE, FALSE
|
||||||
|
'="a" <= "a"', TRUE, TRUE
|
||||||
|
'="A" <= "A"', TRUE, TRUE
|
||||||
|
'="A" <= "a"', TRUE, FALSE
|
||||||
|
'="a" <= "A"', TRUE, TRUE
|
||||||
|
'="a" >= "a"', TRUE, TRUE
|
||||||
|
'="A" >= "A"', TRUE, TRUE
|
||||||
|
'="A" >= "a"', TRUE, TRUE
|
||||||
|
'="a" >= "A"', TRUE, FALSE
|
||||||
|
'="a" <> "a"', FALSE, FALSE
|
||||||
|
'="A" <> "A"', FALSE, FALSE
|
||||||
|
'="A" <> "a"', FALSE, TRUE
|
||||||
|
'="a" <> "A"', FALSE, TRUE
|
||||||
|
'="A" > "b"', FALSE, TRUE
|
||||||
|
'="a" > "b"', FALSE, FALSE
|
||||||
|
'="b" > "a"', TRUE, TRUE
|
||||||
|
'="b" > "A"', TRUE, FALSE
|
||||||
|
'="a2" > "a10"', TRUE, TRUE // Test natural sorting is not used
|
Loading…
Reference in New Issue