Support double-byte chars for formula functions LENB, RIGHTB and MIDB (#1478)

This commit is contained in:
Shugo Kawamura 2023-02-21 01:17:35 +09:00 committed by GitHub
parent 983cd76485
commit f143dd5c34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 11 deletions

46
calc.go
View File

@ -13426,9 +13426,7 @@ func (fn *formulaFuncs) LEFTB(argsList *list.List) formulaArg {
return fn.leftRight("LEFTB", argsList) return fn.leftRight("LEFTB", argsList)
} }
// leftRight is an implementation of the formula functions LEFT, LEFTB, RIGHT, // leftRight is an implementation of the formula functions LEFT, LEFTB, RIGHT, RIGHTB.
// RIGHTB. TODO: support DBCS include Japanese, Chinese (Simplified), Chinese
// (Traditional), and Korean.
func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg { func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg {
if argsList.Len() < 1 { if argsList.Len() < 1 {
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name)) return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
@ -13447,10 +13445,22 @@ func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg {
} }
numChars = int(numArg.Number) 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 utf8.RuneCountInString(text) > numChars {
if name == "LEFT" || name == "LEFTB" { if name == "LEFT" {
return newStringFormulaArg(string([]rune(text)[:numChars])) return newStringFormulaArg(string([]rune(text)[:numChars]))
} }
// RIGHT
return newStringFormulaArg(string([]rune(text)[utf8.RuneCountInString(text)-numChars:])) return newStringFormulaArg(string([]rune(text)[utf8.RuneCountInString(text)-numChars:]))
} }
return newStringFormulaArg(text) return newStringFormulaArg(text)
@ -13480,7 +13490,16 @@ func (fn *formulaFuncs) LENB(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "LENB requires 1 string argument") 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 // LOWER converts all characters in a supplied text string to lower case. The
@ -13528,6 +13547,19 @@ func (fn *formulaFuncs) mid(name string, argsList *list.List) formulaArg {
if startNum < 0 { if startNum < 0 {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) 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) textLen := utf8.RuneCountInString(text)
if startNum > textLen { if startNum > textLen {
return newStringFormulaArg("") return newStringFormulaArg("")
@ -13535,9 +13567,9 @@ func (fn *formulaFuncs) mid(name string, argsList *list.List) formulaArg {
startNum-- startNum--
endNum := startNum + int(numCharsArg.Number) endNum := startNum + int(numCharsArg.Number)
if endNum > textLen+1 { 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 // PROPER converts all characters in a supplied text string to proper case

View File

@ -1709,11 +1709,15 @@ func TestCalcCellValue(t *testing.T) {
"=LEFTB(\"Original Text\",13)": "Original Text", "=LEFTB(\"Original Text\",13)": "Original Text",
"=LEFTB(\"Original Text\",20)": "Original Text", "=LEFTB(\"Original Text\",20)": "Original Text",
// LEN // LEN
"=LEN(\"\")": "0", "=LEN(\"\")": "0",
"=LEN(D1)": "5", "=LEN(D1)": "5",
"=LEN(\"テキスト\")": "4",
"=LEN(\"オリジナルテキスト\")": "9",
// LENB // LENB
"=LENB(\"\")": "0", "=LENB(\"\")": "0",
"=LENB(D1)": "5", "=LENB(D1)": "5",
"=LENB(\"テキスト\")": "8",
"=LENB(\"オリジナルテキスト\")": "18",
// LOWER // LOWER
"=LOWER(\"test\")": "test", "=LOWER(\"test\")": "test",
"=LOWER(\"TEST\")": "test", "=LOWER(\"TEST\")": "test",
@ -1725,6 +1729,8 @@ func TestCalcCellValue(t *testing.T) {
"=MID(\"255 years\",3,1)": "5", "=MID(\"255 years\",3,1)": "5",
"=MID(\"text\",3,6)": "xt", "=MID(\"text\",3,6)": "xt",
"=MID(\"text\",6,0)": "", "=MID(\"text\",6,0)": "",
"=MID(\"オリジナルテキスト\",6,4)": "テキスト",
"=MID(\"オリジナルテキスト\",3,5)": "ジナルテキ",
// MIDB // MIDB
"=MIDB(\"Original Text\",7,1)": "a", "=MIDB(\"Original Text\",7,1)": "a",
"=MIDB(\"Original Text\",4,7)": "ginal T", "=MIDB(\"Original Text\",4,7)": "ginal T",