Skip to content

Commit

Permalink
Support double-byte chars for formula functions LENB, RIGHTB and MIDB (
Browse files Browse the repository at this point in the history
  • Loading branch information
Shugo Kawamura authored Feb 20, 2023
1 parent 983cd76 commit f143dd5
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 11 deletions.
46 changes: 39 additions & 7 deletions calc.go
Original file line number Diff line number Diff line change
Expand Up @@ -13426,9 +13426,7 @@ func (fn *formulaFuncs) LEFTB(argsList *list.List) formulaArg {
return fn.leftRight("LEFTB", argsList)
}

// leftRight is an implementation of the formula functions LEFT, LEFTB, RIGHT,
// RIGHTB. TODO: support DBCS include Japanese, Chinese (Simplified), Chinese
// (Traditional), and Korean.
// leftRight is an implementation of the formula functions LEFT, LEFTB, RIGHT, RIGHTB.
func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg {
if argsList.Len() < 1 {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
Expand All @@ -13447,10 +13445,22 @@ func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg {
}
numChars = int(numArg.Number)
}
if name == "LEFTB" || name == "RIGHTB" {
if len(text) > numChars {
if name == "LEFTB" {
return newStringFormulaArg(text[:numChars])
}
// RIGHTB
return newStringFormulaArg(text[len(text)-numChars:])
}
return newStringFormulaArg(text)
}
// LEFT/RIGHT
if utf8.RuneCountInString(text) > numChars {
if name == "LEFT" || name == "LEFTB" {
if name == "LEFT" {
return newStringFormulaArg(string([]rune(text)[:numChars]))
}
// RIGHT
return newStringFormulaArg(string([]rune(text)[utf8.RuneCountInString(text)-numChars:]))
}
return newStringFormulaArg(text)
Expand Down Expand Up @@ -13480,7 +13490,16 @@ func (fn *formulaFuncs) LENB(argsList *list.List) formulaArg {
if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "LENB requires 1 string argument")
}
return newStringFormulaArg(strconv.Itoa(len(argsList.Front().Value.(formulaArg).String)))
bytes := 0
for _, r := range []rune(argsList.Front().Value.(formulaArg).String) {
b := utf8.RuneLen(r)
if b == 1 {
bytes++
} else if b > 1 {
bytes += 2
}
}
return newStringFormulaArg(strconv.Itoa(bytes))
}

// LOWER converts all characters in a supplied text string to lower case. The
Expand Down Expand Up @@ -13528,16 +13547,29 @@ func (fn *formulaFuncs) mid(name string, argsList *list.List) formulaArg {
if startNum < 0 {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
}
if name == "MIDB" {
textLen := len(text)
if startNum > textLen {
return newStringFormulaArg("")
}
startNum--
endNum := startNum + int(numCharsArg.Number)
if endNum > textLen+1 {
return newStringFormulaArg(text[startNum:])
}
return newStringFormulaArg(text[startNum:endNum])
}
// MID
textLen := utf8.RuneCountInString(text)
if startNum > textLen {
return newStringFormulaArg("")
}
startNum--
endNum := startNum + int(numCharsArg.Number)
if endNum > textLen+1 {
return newStringFormulaArg(text[startNum:])
return newStringFormulaArg(string([]rune(text)[startNum:]))
}
return newStringFormulaArg(text[startNum:endNum])
return newStringFormulaArg(string([]rune(text)[startNum:endNum]))
}

// PROPER converts all characters in a supplied text string to proper case
Expand Down
14 changes: 10 additions & 4 deletions calc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1709,11 +1709,15 @@ func TestCalcCellValue(t *testing.T) {
"=LEFTB(\"Original Text\",13)": "Original Text",
"=LEFTB(\"Original Text\",20)": "Original Text",
// LEN
"=LEN(\"\")": "0",
"=LEN(D1)": "5",
"=LEN(\"\")": "0",
"=LEN(D1)": "5",
"=LEN(\"テキスト\")": "4",
"=LEN(\"オリジナルテキスト\")": "9",
// LENB
"=LENB(\"\")": "0",
"=LENB(D1)": "5",
"=LENB(\"\")": "0",
"=LENB(D1)": "5",
"=LENB(\"テキスト\")": "8",
"=LENB(\"オリジナルテキスト\")": "18",
// LOWER
"=LOWER(\"test\")": "test",
"=LOWER(\"TEST\")": "test",
Expand All @@ -1725,6 +1729,8 @@ func TestCalcCellValue(t *testing.T) {
"=MID(\"255 years\",3,1)": "5",
"=MID(\"text\",3,6)": "xt",
"=MID(\"text\",6,0)": "",
"=MID(\"オリジナルテキスト\",6,4)": "テキスト",
"=MID(\"オリジナルテキスト\",3,5)": "ジナルテキ",
// MIDB
"=MIDB(\"Original Text\",7,1)": "a",
"=MIDB(\"Original Text\",4,7)": "ginal T",
Expand Down

0 comments on commit f143dd5

Please sign in to comment.