@@ -50,8 +50,10 @@ class Calculation
50
50
const RETURN_ARRAY_AS_VALUE = 'value ' ;
51
51
const RETURN_ARRAY_AS_ARRAY = 'array ' ;
52
52
53
- const FORMULA_OPEN_FUNCTION_BRACE = '{ ' ;
54
- const FORMULA_CLOSE_FUNCTION_BRACE = '} ' ;
53
+ const FORMULA_OPEN_FUNCTION_BRACE = '( ' ;
54
+ const FORMULA_CLOSE_FUNCTION_BRACE = ') ' ;
55
+ const FORMULA_OPEN_MATRIX_BRACE = '{ ' ;
56
+ const FORMULA_CLOSE_MATRIX_BRACE = '} ' ;
55
57
const FORMULA_STRING_QUOTE = '" ' ;
56
58
57
59
private static $ returnArrayAsType = self ::RETURN_ARRAY_AS_VALUE ;
@@ -3084,30 +3086,28 @@ public function setLocale(string $locale)
3084
3086
return false ;
3085
3087
}
3086
3088
3087
- /**
3088
- * @param string $fromSeparator
3089
- * @param string $toSeparator
3090
- * @param string $formula
3091
- * @param bool $inBraces
3092
- *
3093
- * @return string
3094
- */
3095
- public static function translateSeparator ($ fromSeparator , $ toSeparator , $ formula , &$ inBraces )
3096
- {
3089
+ public static function translateSeparator (
3090
+ string $ fromSeparator ,
3091
+ string $ toSeparator ,
3092
+ string $ formula ,
3093
+ int &$ inBracesLevel ,
3094
+ string $ openBrace = self ::FORMULA_OPEN_FUNCTION_BRACE ,
3095
+ string $ closeBrace = self ::FORMULA_CLOSE_FUNCTION_BRACE
3096
+ ): string {
3097
3097
$ strlen = mb_strlen ($ formula );
3098
3098
for ($ i = 0 ; $ i < $ strlen ; ++$ i ) {
3099
3099
$ chr = mb_substr ($ formula , $ i , 1 );
3100
3100
switch ($ chr ) {
3101
- case self :: FORMULA_OPEN_FUNCTION_BRACE :
3102
- $ inBraces = true ;
3101
+ case $ openBrace :
3102
+ ++ $ inBracesLevel ;
3103
3103
3104
3104
break ;
3105
- case self :: FORMULA_CLOSE_FUNCTION_BRACE :
3106
- $ inBraces = false ;
3105
+ case $ closeBrace :
3106
+ -- $ inBracesLevel ;
3107
3107
3108
3108
break ;
3109
3109
case $ fromSeparator :
3110
- if (! $ inBraces ) {
3110
+ if ($ inBracesLevel > 0 ) {
3111
3111
$ formula = mb_substr ($ formula , 0 , $ i ) . $ toSeparator . mb_substr ($ formula , $ i + 1 );
3112
3112
}
3113
3113
}
@@ -3116,40 +3116,55 @@ public static function translateSeparator($fromSeparator, $toSeparator, $formula
3116
3116
return $ formula ;
3117
3117
}
3118
3118
3119
- /**
3120
- * @param string[] $from
3121
- * @param string[] $to
3122
- * @param string $formula
3123
- * @param string $fromSeparator
3124
- * @param string $toSeparator
3125
- *
3126
- * @return string
3127
- */
3128
- private static function translateFormula (array $ from , array $ to , $ formula , $ fromSeparator , $ toSeparator )
3119
+ private static function translateFormulaBlock (
3120
+ array $ from ,
3121
+ array $ to ,
3122
+ string $ formula ,
3123
+ int &$ inFunctionBracesLevel ,
3124
+ int &$ inMatrixBracesLevel ,
3125
+ string $ fromSeparator ,
3126
+ string $ toSeparator
3127
+ ): string {
3128
+ // Function Names
3129
+ $ formula = preg_replace ($ from , $ to , $ formula );
3130
+
3131
+ // Temporarily adjust matrix separators so that they won't be confused with function arguments
3132
+ $ formula = self ::translateSeparator ('; ' , '| ' , $ formula , $ inMatrixBracesLevel , self ::FORMULA_OPEN_MATRIX_BRACE , self ::FORMULA_CLOSE_MATRIX_BRACE );
3133
+ $ formula = self ::translateSeparator (', ' , '! ' , $ formula , $ inMatrixBracesLevel , self ::FORMULA_OPEN_MATRIX_BRACE , self ::FORMULA_CLOSE_MATRIX_BRACE );
3134
+ // Function Argument Separators
3135
+ $ formula = self ::translateSeparator ($ fromSeparator , $ toSeparator , $ formula , $ inFunctionBracesLevel );
3136
+ // Restore matrix separators
3137
+ $ formula = self ::translateSeparator ('| ' , '; ' , $ formula , $ inMatrixBracesLevel , self ::FORMULA_OPEN_MATRIX_BRACE , self ::FORMULA_CLOSE_MATRIX_BRACE );
3138
+ $ formula = self ::translateSeparator ('! ' , ', ' , $ formula , $ inMatrixBracesLevel , self ::FORMULA_OPEN_MATRIX_BRACE , self ::FORMULA_CLOSE_MATRIX_BRACE );
3139
+
3140
+ return $ formula ;
3141
+ }
3142
+
3143
+ private static function translateFormula (array $ from , array $ to , string $ formula , string $ fromSeparator , string $ toSeparator ): string
3129
3144
{
3130
- // Convert any Excel function names to the required language
3145
+ // Convert any Excel function names and constant names to the required language;
3146
+ // and adjust function argument separators
3131
3147
if (self ::$ localeLanguage !== 'en_us ' ) {
3132
- $ inBraces = false ;
3133
- // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
3148
+ $ inFunctionBracesLevel = 0 ;
3149
+ $ inMatrixBracesLevel = 0 ;
3150
+ // If there is the possibility of separators within a quoted string, then we treat them as literals
3134
3151
if (strpos ($ formula , self ::FORMULA_STRING_QUOTE ) !== false ) {
3135
- // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
3136
- // the formula
3152
+ // So instead we skip replacing in any quoted strings by only replacing in every other array element
3153
+ // after we've exploded the formula
3137
3154
$ temp = explode (self ::FORMULA_STRING_QUOTE , $ formula );
3138
3155
$ i = false ;
3139
3156
foreach ($ temp as &$ value ) {
3140
- // Only count/replace in alternating array entries
3157
+ // Only adjust in alternating array entries
3141
3158
if ($ i = !$ i ) {
3142
- $ value = preg_replace ($ from , $ to , $ value );
3143
- $ value = self ::translateSeparator ($ fromSeparator , $ toSeparator , $ value , $ inBraces );
3159
+ $ value = self ::translateFormulaBlock ($ from , $ to , $ value , $ inFunctionBracesLevel , $ inMatrixBracesLevel , $ fromSeparator , $ toSeparator );
3144
3160
}
3145
3161
}
3146
3162
unset($ value );
3147
3163
// Then rebuild the formula string
3148
3164
$ formula = implode (self ::FORMULA_STRING_QUOTE , $ temp );
3149
3165
} else {
3150
3166
// If there's no quoted strings, then we do a simple count/replace
3151
- $ formula = preg_replace ($ from , $ to , $ formula );
3152
- $ formula = self ::translateSeparator ($ fromSeparator , $ toSeparator , $ formula , $ inBraces );
3167
+ $ formula = self ::translateFormulaBlock ($ from , $ to , $ formula , $ inFunctionBracesLevel , $ inMatrixBracesLevel , $ fromSeparator , $ toSeparator );
3153
3168
}
3154
3169
}
3155
3170
@@ -3162,6 +3177,7 @@ private static function translateFormula(array $from, array $to, $formula, $from
3162
3177
3163
3178
public function _translateFormulaToLocale ($ formula )
3164
3179
{
3180
+ // Build list of function names and constants for translation
3165
3181
if (self ::$ functionReplaceFromExcel === null ) {
3166
3182
self ::$ functionReplaceFromExcel = [];
3167
3183
foreach (array_keys (self ::$ localeFunctions ) as $ excelFunctionName ) {
@@ -3798,11 +3814,11 @@ private function showTypeDetails($value)
3798
3814
*/
3799
3815
private function convertMatrixReferences ($ formula )
3800
3816
{
3801
- static $ matrixReplaceFrom = [self ::FORMULA_OPEN_FUNCTION_BRACE , '; ' , self ::FORMULA_CLOSE_FUNCTION_BRACE ];
3817
+ static $ matrixReplaceFrom = [self ::FORMULA_OPEN_MATRIX_BRACE , '; ' , self ::FORMULA_CLOSE_MATRIX_BRACE ];
3802
3818
static $ matrixReplaceTo = ['MKMATRIX(MKMATRIX( ' , '),MKMATRIX( ' , ')) ' ];
3803
3819
3804
3820
// Convert any Excel matrix references to the MKMATRIX() function
3805
- if (strpos ($ formula , self ::FORMULA_OPEN_FUNCTION_BRACE ) !== false ) {
3821
+ if (strpos ($ formula , self ::FORMULA_OPEN_MATRIX_BRACE ) !== false ) {
3806
3822
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
3807
3823
if (strpos ($ formula , self ::FORMULA_STRING_QUOTE ) !== false ) {
3808
3824
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
@@ -3814,8 +3830,8 @@ private function convertMatrixReferences($formula)
3814
3830
foreach ($ temp as &$ value ) {
3815
3831
// Only count/replace in alternating array entries
3816
3832
if ($ i = !$ i ) {
3817
- $ openCount += substr_count ($ value , self ::FORMULA_OPEN_FUNCTION_BRACE );
3818
- $ closeCount += substr_count ($ value , self ::FORMULA_CLOSE_FUNCTION_BRACE );
3833
+ $ openCount += substr_count ($ value , self ::FORMULA_OPEN_MATRIX_BRACE );
3834
+ $ closeCount += substr_count ($ value , self ::FORMULA_CLOSE_MATRIX_BRACE );
3819
3835
$ value = str_replace ($ matrixReplaceFrom , $ matrixReplaceTo , $ value );
3820
3836
}
3821
3837
}
@@ -3824,8 +3840,8 @@ private function convertMatrixReferences($formula)
3824
3840
$ formula = implode (self ::FORMULA_STRING_QUOTE , $ temp );
3825
3841
} else {
3826
3842
// If there's no quoted strings, then we do a simple count/replace
3827
- $ openCount = substr_count ($ formula , self ::FORMULA_OPEN_FUNCTION_BRACE );
3828
- $ closeCount = substr_count ($ formula , self ::FORMULA_CLOSE_FUNCTION_BRACE );
3843
+ $ openCount = substr_count ($ formula , self ::FORMULA_OPEN_MATRIX_BRACE );
3844
+ $ closeCount = substr_count ($ formula , self ::FORMULA_CLOSE_MATRIX_BRACE );
3829
3845
$ formula = str_replace ($ matrixReplaceFrom , $ matrixReplaceTo , $ formula );
3830
3846
}
3831
3847
// Trap for mismatched braces and trigger an appropriate error
0 commit comments