@@ -421,7 +421,7 @@ public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $hei
421
421
* @param mixed $index_num Specifies which value argument is selected.
422
422
* Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
423
423
* between 1 and 254.
424
- * @param mixed $value1... Value1 is required, subsequent values are optional.
424
+ * @param mixed $value1 ... Value1 is required, subsequent values are optional.
425
425
* Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
426
426
* index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
427
427
* text.
@@ -709,24 +709,33 @@ public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not
709
709
710
710
$ rowNumber = $ rowValue = false ;
711
711
foreach ($ lookup_array as $ rowKey => $ rowData ) {
712
+ // break if we have passed possible keys
712
713
if ((is_numeric ($ lookup_value ) && is_numeric ($ rowData [$ firstColumn ]) && ($ rowData [$ firstColumn ] > $ lookup_value )) ||
713
714
(!is_numeric ($ lookup_value ) && !is_numeric ($ rowData [$ firstColumn ]) && (strtolower ($ rowData [$ firstColumn ]) > strtolower ($ lookup_value )))) {
714
715
break ;
715
716
}
716
717
// remember the last key, but only if datatypes match
717
718
if ((is_numeric ($ lookup_value ) && is_numeric ($ rowData [$ firstColumn ])) ||
718
719
(!is_numeric ($ lookup_value ) && !is_numeric ($ rowData [$ firstColumn ]))) {
719
- $ rowNumber = $ rowKey ;
720
- $ rowValue = $ rowData [$ firstColumn ];
720
+ if ($ not_exact_match ) {
721
+ $ rowNumber = $ rowKey ;
722
+ $ rowValue = $ rowData [$ firstColumn ];
723
+
724
+ continue ;
725
+ } elseif ((strtolower ($ rowData [$ firstColumn ]) == strtolower ($ lookup_value ))
726
+ // Spreadsheets software returns first exact match,
727
+ // we have sorted and we might have broken key orders
728
+ // we want the first one (by its initial index)
729
+ && (($ rowNumber == false ) || ($ rowKey < $ rowNumber ))
730
+ ) {
731
+ $ rowNumber = $ rowKey ;
732
+ $ rowValue = $ rowData [$ firstColumn ];
733
+ }
721
734
}
722
735
}
723
736
724
737
if ($ rowNumber !== false ) {
725
- if ((!$ not_exact_match ) && ($ rowValue != $ lookup_value )) {
726
- // if an exact match is required, we have what we need to return an appropriate response
727
- return Functions::NA ();
728
- }
729
- // otherwise return the appropriate value
738
+ // return the appropriate value
730
739
return $ lookup_array [$ rowNumber ][$ returnColumn ];
731
740
}
732
741
@@ -764,29 +773,35 @@ public static function HLOOKUP($lookup_value, $lookup_array, $index_number, $not
764
773
if ((!is_array ($ lookup_array [$ firstRow ])) || ($ index_number > count ($ lookup_array ))) {
765
774
return Functions::REF ();
766
775
}
767
- $ columnKeys = array_keys ( $ lookup_array [ $ firstRow ]);
776
+
768
777
$ firstkey = $ f [0 ] - 1 ;
769
778
$ returnColumn = $ firstkey + $ index_number ;
770
779
$ firstColumn = array_shift ($ f );
771
-
772
- if (!$ not_exact_match ) {
773
- $ firstRowH = asort ($ lookup_array [$ firstColumn ]);
774
- }
775
- $ rowNumber = $ rowValue = false ;
780
+ $ rowNumber = null ;
776
781
foreach ($ lookup_array [$ firstColumn ] as $ rowKey => $ rowData ) {
777
- if ((is_numeric ($ lookup_value ) && is_numeric ($ rowData ) && ($ rowData > $ lookup_value )) ||
778
- (!is_numeric ($ lookup_value ) && !is_numeric ($ rowData ) && (strtolower ($ rowData ) > strtolower ($ lookup_value )))) {
782
+ // break if we have passed possible keys
783
+ $ bothNumeric = is_numeric ($ lookup_value ) && is_numeric ($ rowData );
784
+ $ bothNotNumeric = !is_numeric ($ lookup_value ) && !is_numeric ($ rowData );
785
+ if (($ bothNumeric && $ rowData > $ lookup_value ) ||
786
+ ($ bothNotNumeric && strtolower ($ rowData ) > strtolower ($ lookup_value ))) {
779
787
break ;
780
788
}
781
- $ rowNumber = $ rowKey ;
782
- $ rowValue = $ rowData ;
783
- }
784
789
785
- if ($ rowNumber !== false ) {
786
- if ((!$ not_exact_match ) && ($ rowValue != $ lookup_value )) {
787
- // if an exact match is required, we have what we need to return an appropriate response
788
- return Functions::NA ();
790
+ // Remember the last key, but only if datatypes match (as in VLOOKUP)
791
+ if ($ bothNumeric || $ bothNotNumeric ) {
792
+ if ($ not_exact_match ) {
793
+ $ rowNumber = $ rowKey ;
794
+
795
+ continue ;
796
+ } elseif (strtolower ($ rowData ) === strtolower ($ lookup_value )
797
+ && ($ rowNumber === null || $ rowKey < $ rowNumber )
798
+ ) {
799
+ $ rowNumber = $ rowKey ;
800
+ }
789
801
}
802
+ }
803
+
804
+ if ($ rowNumber !== null ) {
790
805
// otherwise return the appropriate value
791
806
return $ lookup_array [$ returnColumn ][$ rowNumber ];
792
807
}
0 commit comments