Skip to content

Commit eaee8d4

Browse files
simeonkorchevSimeon Korchev
andauthored
Fix string exact matching (#3)
Co-authored-by: Simeon Korchev <korchev@abraxa.com>
1 parent 701fc83 commit eaee8d4

File tree

2 files changed

+76
-60
lines changed

2 files changed

+76
-60
lines changed

calc.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15156,7 +15156,19 @@ func (fn *formulaFuncs) MATCH(argsList *list.List) formulaArg {
1515615156
default:
1515715157
return newErrorFormulaArg(formulaErrorNA, lookupArrayErr)
1515815158
}
15159-
return calcMatch(matchType, formulaCriteriaParser(argsList.Front().Value.(formulaArg)), lookupArray)
15159+
15160+
// When dealing with string values that do not match any of the regex patterns defined in formulaFormats,
15161+
// the criteria type will default to 'criteriaRegexp'.
15162+
// In cases of exact matches, this causes the formulaCriteriaEval to match substrings within the lookupArray,
15163+
// which conflicts with the intended behavior of exact matching.
15164+
// To address this issue, the condition value is modified by appending '^' at the beginning and '$' at the end,
15165+
// ensuring that the regex matches the exact string, rather than partial matches.
15166+
criteria := formulaCriteriaParser(argsList.Front().Value.(formulaArg))
15167+
if matchType == matchModeExact && criteria.Type == criteriaRegexp && criteria.Condition.Type == ArgString {
15168+
criteria.Condition = newStringFormulaArg("^" + criteria.Condition.Value() + "$")
15169+
}
15170+
15171+
return calcMatch(matchType, criteria, lookupArray)
1516015172
}
1516115173

1516215174
// TRANSPOSE function 'transposes' an array of cells (i.e. the function copies

calc_test.go

Lines changed: 63 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -777,25 +777,25 @@ func TestCalcCellValue(t *testing.T) {
777777
"=ROUNDUP(-11.111,-1)": "-20",
778778
"=ROUNDUP(ROUNDUP(100,1),-1)": "100",
779779
// SEARCH
780-
"=SEARCH(\"s\",F1)": "1",
781-
"=SEARCH(\"s\",F1,2)": "5",
782-
"=SEARCH(\"e\",F1)": "4",
783-
"=SEARCH(\"e*\",F1)": "4",
784-
"=SEARCH(\"?e\",F1)": "3",
785-
"=SEARCH(\"??e\",F1)": "2",
786-
"=SEARCH(6,F2)": "2",
780+
"=SEARCH(\"s\",F1)": "1",
781+
"=SEARCH(\"s\",F1,2)": "5",
782+
"=SEARCH(\"e\",F1)": "4",
783+
"=SEARCH(\"e*\",F1)": "4",
784+
"=SEARCH(\"?e\",F1)": "3",
785+
"=SEARCH(\"??e\",F1)": "2",
786+
"=SEARCH(6,F2)": "2",
787787
"=SEARCH(\"?\",\"你好world\")": "1",
788788
"=SEARCH(\"?l\",\"你好world\")": "5",
789789
"=SEARCH(\"?+\",\"你好 1+2\")": "4",
790790
"=SEARCH(\" ?+\",\"你好 1+2\")": "3",
791791
// SEARCHB
792-
"=SEARCHB(\"s\",F1)": "1",
793-
"=SEARCHB(\"s\",F1,2)": "5",
794-
"=SEARCHB(\"e\",F1)": "4",
795-
"=SEARCHB(\"e*\",F1)": "4",
796-
"=SEARCHB(\"?e\",F1)": "3",
797-
"=SEARCHB(\"??e\",F1)": "2",
798-
"=SEARCHB(6,F2)": "2",
792+
"=SEARCHB(\"s\",F1)": "1",
793+
"=SEARCHB(\"s\",F1,2)": "5",
794+
"=SEARCHB(\"e\",F1)": "4",
795+
"=SEARCHB(\"e*\",F1)": "4",
796+
"=SEARCHB(\"?e\",F1)": "3",
797+
"=SEARCHB(\"??e\",F1)": "2",
798+
"=SEARCHB(6,F2)": "2",
799799
"=SEARCHB(\"?\",\"你好world\")": "5",
800800
"=SEARCHB(\"?l\",\"你好world\")": "7",
801801
"=SEARCHB(\"?+\",\"你好 1+2\")": "6",
@@ -1764,33 +1764,33 @@ func TestCalcCellValue(t *testing.T) {
17641764
"=FINDB(\"\",\"Original Text\",2)": "2",
17651765
"=FINDB(\"s\",\"Sales\",2)": "5",
17661766
// LEFT
1767-
"=LEFT(\"Original Text\")": "O",
1768-
"=LEFT(\"Original Text\",4)": "Orig",
1769-
"=LEFT(\"Original Text\",0)": "",
1770-
"=LEFT(\"Original Text\",13)": "Original Text",
1771-
"=LEFT(\"Original Text\",20)": "Original Text",
1772-
"=LEFT(\"オリジナルテキスト\")": "オ",
1773-
"=LEFT(\"オリジナルテキスト\",2)": "オリ",
1774-
"=LEFT(\"オリジナルテキスト\",5)": "オリジナル",
1775-
"=LEFT(\"オリジナルテキスト\",7)": "オリジナルテキ",
1776-
"=LEFT(\"オリジナルテキスト\",20)": "オリジナルテキスト",
1767+
"=LEFT(\"Original Text\")": "O",
1768+
"=LEFT(\"Original Text\",4)": "Orig",
1769+
"=LEFT(\"Original Text\",0)": "",
1770+
"=LEFT(\"Original Text\",13)": "Original Text",
1771+
"=LEFT(\"Original Text\",20)": "Original Text",
1772+
"=LEFT(\"オリジナルテキスト\")": "オ",
1773+
"=LEFT(\"オリジナルテキスト\",2)": "オリ",
1774+
"=LEFT(\"オリジナルテキスト\",5)": "オリジナル",
1775+
"=LEFT(\"オリジナルテキスト\",7)": "オリジナルテキ",
1776+
"=LEFT(\"オリジナルテキスト\",20)": "オリジナルテキスト",
17771777
// LEFTB
17781778
"=LEFTB(\"Original Text\")": "O",
17791779
"=LEFTB(\"Original Text\",4)": "Orig",
17801780
"=LEFTB(\"Original Text\",0)": "",
17811781
"=LEFTB(\"Original Text\",13)": "Original Text",
17821782
"=LEFTB(\"Original Text\",20)": "Original Text",
17831783
// LEN
1784-
"=LEN(\"\")": "0",
1785-
"=LEN(D1)": "5",
1786-
"=LEN(\"テキスト\")": "4",
1787-
"=LEN(\"オリジナルテキスト\")": "9",
1788-
"=LEN(7+LEN(A1&B1&C1))": "1",
1789-
"=LEN(8+LEN(A1+(C1-B1)))": "2",
1784+
"=LEN(\"\")": "0",
1785+
"=LEN(D1)": "5",
1786+
"=LEN(\"テキスト\")": "4",
1787+
"=LEN(\"オリジナルテキスト\")": "9",
1788+
"=LEN(7+LEN(A1&B1&C1))": "1",
1789+
"=LEN(8+LEN(A1+(C1-B1)))": "2",
17901790
// LENB
1791-
"=LENB(\"\")": "0",
1792-
"=LENB(D1)": "5",
1793-
"=LENB(\"テキスト\")": "8",
1791+
"=LENB(\"\")": "0",
1792+
"=LENB(D1)": "5",
1793+
"=LENB(\"テキスト\")": "8",
17941794
"=LENB(\"オリジナルテキスト\")": "18",
17951795
// LOWER
17961796
"=LOWER(\"test\")": "test",
@@ -1803,7 +1803,7 @@ func TestCalcCellValue(t *testing.T) {
18031803
"=MID(\"255 years\",3,1)": "5",
18041804
"=MID(\"text\",3,6)": "xt",
18051805
"=MID(\"text\",6,0)": "",
1806-
"=MID(\"你好World\",5,1)": "r",
1806+
"=MID(\"你好World\",5,1)": "r",
18071807
"=MID(\"\u30AA\u30EA\u30B8\u30CA\u30EB\u30C6\u30AD\u30B9\u30C8\",6,4)": "\u30C6\u30AD\u30B9\u30C8",
18081808
"=MID(\"\u30AA\u30EA\u30B8\u30CA\u30EB\u30C6\u30AD\u30B9\u30C8\",3,5)": "\u30B8\u30CA\u30EB\u30C6\u30AD",
18091809
// MIDB
@@ -1812,7 +1812,7 @@ func TestCalcCellValue(t *testing.T) {
18121812
"=MIDB(\"255 years\",3,1)": "5",
18131813
"=MIDB(\"text\",3,6)": "xt",
18141814
"=MIDB(\"text\",6,0)": "",
1815-
"=MIDB(\"你好World\",5,1)": "W",
1815+
"=MIDB(\"你好World\",5,1)": "W",
18161816
"=MIDB(\"\u30AA\u30EA\u30B8\u30CA\u30EB\u30C6\u30AD\u30B9\u30C8\",6,4)": "\u30B8\u30CA",
18171817
"=MIDB(\"\u30AA\u30EA\u30B8\u30CA\u30EB\u30C6\u30AD\u30B9\u30C8\",3,5)": "\u30EA\u30B8\xe3",
18181818
// PROPER
@@ -1835,16 +1835,16 @@ func TestCalcCellValue(t *testing.T) {
18351835
"=REPT(\"*\",1)": "*",
18361836
"=REPT(\"**\",2)": "****",
18371837
// RIGHT
1838-
"=RIGHT(\"Original Text\")": "t",
1839-
"=RIGHT(\"Original Text\",4)": "Text",
1840-
"=RIGHT(\"Original Text\",0)": "",
1841-
"=RIGHT(\"Original Text\",13)": "Original Text",
1842-
"=RIGHT(\"Original Text\",20)": "Original Text",
1843-
"=RIGHT(\"オリジナルテキスト\")": "ト",
1844-
"=RIGHT(\"オリジナルテキスト\",2)": "スト",
1845-
"=RIGHT(\"オリジナルテキスト\",4)": "テキスト",
1846-
"=RIGHT(\"オリジナルテキスト\",7)": "ジナルテキスト",
1847-
"=RIGHT(\"オリジナルテキスト\",20)": "オリジナルテキスト",
1838+
"=RIGHT(\"Original Text\")": "t",
1839+
"=RIGHT(\"Original Text\",4)": "Text",
1840+
"=RIGHT(\"Original Text\",0)": "",
1841+
"=RIGHT(\"Original Text\",13)": "Original Text",
1842+
"=RIGHT(\"Original Text\",20)": "Original Text",
1843+
"=RIGHT(\"オリジナルテキスト\")": "ト",
1844+
"=RIGHT(\"オリジナルテキスト\",2)": "スト",
1845+
"=RIGHT(\"オリジナルテキスト\",4)": "テキスト",
1846+
"=RIGHT(\"オリジナルテキスト\",7)": "ジナルテキスト",
1847+
"=RIGHT(\"オリジナルテキスト\",20)": "オリジナルテキスト",
18481848
// RIGHTB
18491849
"=RIGHTB(\"Original Text\")": "t",
18501850
"=RIGHTB(\"Original Text\",4)": "Text",
@@ -2806,11 +2806,11 @@ func TestCalcCellValue(t *testing.T) {
28062806
"=SEARCH(2,A1)": {"#VALUE!", "#VALUE!"},
28072807
"=SEARCH(1,A1,\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
28082808
// SEARCHB
2809-
"=SEARCHB()": {"#VALUE!", "SEARCHB requires at least 2 arguments"},
2810-
"=SEARCHB(1,A1,1,1)": {"#VALUE!", "SEARCHB allows at most 3 arguments"},
2811-
"=SEARCHB(2,A1)": {"#VALUE!", "#VALUE!"},
2809+
"=SEARCHB()": {"#VALUE!", "SEARCHB requires at least 2 arguments"},
2810+
"=SEARCHB(1,A1,1,1)": {"#VALUE!", "SEARCHB allows at most 3 arguments"},
2811+
"=SEARCHB(2,A1)": {"#VALUE!", "#VALUE!"},
28122812
"=SEARCHB(\"?w\",\"你好world\")": {"#VALUE!", "#VALUE!"},
2813-
"=SEARCHB(1,A1,\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
2813+
"=SEARCHB(1,A1,\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
28142814
// SEC
28152815
"=_xlfn.SEC()": {"#VALUE!", "SEC requires 1 numeric argument"},
28162816
"=_xlfn.SEC(\"X\")": {"#VALUE!", "strconv.ParseFloat: parsing \"X\": invalid syntax"},
@@ -5775,20 +5775,24 @@ func TestCalcMATCH(t *testing.T) {
57755775
"A4": {"bbbb", 1, 10, 7},
57765776
"A5": {"eeee", 8, 11, 6},
57775777
"A6": {nil, 11, 16, 4},
5778+
"A7": {"exactmatchsubstring", 1, 2, 3},
5779+
"A8": {"exactmatch", 4, 5, 6},
57785780
} {
57795781
assert.NoError(t, f.SetSheetRow("Sheet1", cell, &row))
57805782
}
57815783
formulaList := map[string]string{
5782-
"=MATCH(\"aaaa\",A1:A6,0)": "3",
5783-
"=MATCH(\"*b\",A1:A5,0)": "4",
5784-
"=MATCH(\"?eee\",A1:A5,0)": "5",
5785-
"=MATCH(\"?*?e\",A1:A5,0)": "5",
5786-
"=MATCH(\"aaaa\",A1:A6,1)": "3",
5787-
"=MATCH(10,B1:B6)": "5",
5788-
"=MATCH(8,C1:C6,1)": "3",
5789-
"=MATCH(6,B1:B6,-1)": "1",
5790-
"=MATCH(10,D1:D6,-1)": "3",
5791-
"=MATCH(-10,D1:D6,-1)": "6",
5784+
"=MATCH(\"aaaa\",A1:A6,0)": "3",
5785+
"=MATCH(\"*b\",A1:A5,0)": "4",
5786+
"=MATCH(\"?eee\",A1:A5,0)": "5",
5787+
"=MATCH(\"?*?e\",A1:A5,0)": "5",
5788+
"=MATCH(\"aaaa\",A1:A6,1)": "3",
5789+
"=MATCH(10,B1:B6)": "5",
5790+
"=MATCH(8,C1:C6,1)": "3",
5791+
"=MATCH(6,B1:B6,-1)": "1",
5792+
"=MATCH(10,D1:D6,-1)": "3",
5793+
"=MATCH(-10,D1:D6,-1)": "6",
5794+
"=MATCH(\"exactmatch\",A1:A8,0)": "8",
5795+
"=MATCH(6,D1:D6,0)": "5",
57925796
}
57935797
for formula, expected := range formulaList {
57945798
assert.NoError(t, f.SetCellFormula("Sheet1", "E1", formula))

0 commit comments

Comments
 (0)