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($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
|
||||
switch ($operation) {
|
||||
// Greater than
|
||||
case '>':
|
||||
if ($useLowercaseFirstComparison) {
|
||||
$result = $this->strcmpLowercaseFirst($operand1, $operand2) > 0;
|
||||
} else {
|
||||
$result = ($operand1 > $operand2);
|
||||
}
|
||||
break;
|
||||
// Less than
|
||||
case '<':
|
||||
if ($useLowercaseFirstComparison) {
|
||||
$result = $this->strcmpLowercaseFirst($operand1, $operand2) < 0;
|
||||
} else {
|
||||
$result = ($operand1 < $operand2);
|
||||
}
|
||||
break;
|
||||
// Equality
|
||||
case '=':
|
||||
|
@ -3573,11 +3595,19 @@ class PHPExcel_Calculation {
|
|||
break;
|
||||
// Greater than or equal
|
||||
case '>=':
|
||||
if ($useLowercaseFirstComparison) {
|
||||
$result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0;
|
||||
} else {
|
||||
$result = ($operand1 >= $operand2);
|
||||
}
|
||||
break;
|
||||
// Less than or equal
|
||||
case '<=':
|
||||
if ($useLowercaseFirstComparison) {
|
||||
$result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0;
|
||||
} else {
|
||||
$result = ($operand1 <= $operand2);
|
||||
}
|
||||
break;
|
||||
// Inequality
|
||||
case '<>':
|
||||
|
@ -3592,6 +3622,21 @@ class PHPExcel_Calculation {
|
|||
return TRUE;
|
||||
} // 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) {
|
||||
// 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