Merge pull request #270 from PowerKiKi/issue_31

Binary comparaison of strings are case insensitive
This commit is contained in:
Mark Baker 2013-11-23 13:36:16 -08:00
commit 56c9d079d1
3 changed files with 137 additions and 4 deletions

View File

@ -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

View File

@ -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');
}
}

View File

@ -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