mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
formula: compatibility & bug fixes
- Make UNICODE with no arguments behave like Excel - Fix OFFSET/INDEX for named ranges
This commit is contained in:
parent
e7da598399
commit
0e09e64818
@ -7,7 +7,10 @@
|
||||
|
||||
package formula
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterFunction("INDEX", Index)
|
||||
@ -51,7 +54,12 @@ func Index(args []Result) Result {
|
||||
return MakeErrorResult("INDEX has col out of range")
|
||||
}
|
||||
|
||||
return rowVal[col]
|
||||
rv := rowVal[col]
|
||||
// empty cell returns a zero
|
||||
if rv.Type == ResultTypeEmpty {
|
||||
return MakeNumberResult(0)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// Indirect is an implementation of the Excel INDIRECT function that returns the
|
||||
@ -72,12 +80,20 @@ func Offset(ctx Context, ev Evaluator, args []Result) Result {
|
||||
return MakeErrorResult("OFFSET requires one or two arguments")
|
||||
}
|
||||
ref := args[0].Ref
|
||||
origin := "A1"
|
||||
// resolve a named range
|
||||
for ref.Type == ReferenceTypeNamedRange {
|
||||
ref = ctx.NamedRange(ref.Value)
|
||||
}
|
||||
|
||||
origin := ""
|
||||
switch ref.Type {
|
||||
case ReferenceTypeCell:
|
||||
origin = ref.Value
|
||||
case ReferenceTypeRange:
|
||||
case ReferenceTypeNamedRange:
|
||||
sp := strings.Split(ref.Value, ":")
|
||||
if len(sp) == 2 {
|
||||
origin = sp[0]
|
||||
}
|
||||
default:
|
||||
return MakeErrorResult(fmt.Sprintf("Invalid range in OFFSET(): %s", ref.Type))
|
||||
}
|
||||
@ -91,27 +107,26 @@ func Offset(ctx Context, ev Evaluator, args []Result) Result {
|
||||
if rOff.Type != ResultTypeNumber {
|
||||
return MakeErrorResult("OFFSET requires numeric row offset")
|
||||
}
|
||||
cOff := args[1].AsNumber()
|
||||
cOff := args[2].AsNumber()
|
||||
if cOff.Type != ResultTypeNumber {
|
||||
return MakeErrorResult("OFFSET requires numeric col offset")
|
||||
}
|
||||
|
||||
height := args[1].AsNumber()
|
||||
height := args[3].AsNumber()
|
||||
if height.Type != ResultTypeNumber {
|
||||
return MakeErrorResult("OFFSET requires numeric height")
|
||||
}
|
||||
width := args[1].AsNumber()
|
||||
width := args[4].AsNumber()
|
||||
if width.Type != ResultTypeNumber {
|
||||
return MakeErrorResult("OFFSET requires numeric width")
|
||||
}
|
||||
colIdx := ColumnToIndex(col)
|
||||
origRow := rowIdx + uint32(rOff.ValueNumber)
|
||||
origCol := colIdx + uint32(cOff.ValueNumber)
|
||||
endRow := origRow + uint32(height.ValueNumber)
|
||||
endCol := origCol + uint32(width.ValueNumber)
|
||||
endRow := origRow + uint32(height.ValueNumber) - 1
|
||||
endCol := origCol + uint32(width.ValueNumber) - 1
|
||||
|
||||
beg := fmt.Sprintf("%s%d", IndexToColumn(origCol), origRow)
|
||||
end := fmt.Sprintf("%s%d", IndexToColumn(endCol), endRow)
|
||||
return resultFromCellRange(ctx, ev, beg, end)
|
||||
|
||||
}
|
||||
|
@ -106,6 +106,10 @@ func IfError(args []Result) Result {
|
||||
}
|
||||
|
||||
if args[0].Type != ResultTypeError {
|
||||
// empty cell returns a zero
|
||||
if args[0].Type == ResultTypeEmpty {
|
||||
return MakeNumberResult(0)
|
||||
}
|
||||
return args[0]
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ func init() {
|
||||
//RegisterFunction("TEXTJOIN")
|
||||
RegisterFunction("TRIM", Trim)
|
||||
RegisterFunction("_xlfn.UNICHAR", Char) // for now
|
||||
RegisterFunction("_xlfn.UNICODE", Code) // for now
|
||||
RegisterFunction("_xlfn.UNICODE", Unicode)
|
||||
RegisterFunction("UPPER", Upper)
|
||||
//RegisterFunction("VALUE", )
|
||||
}
|
||||
@ -109,6 +109,22 @@ func Code(args []Result) Result {
|
||||
return MakeNumberResult(float64(s.ValueString[0]))
|
||||
}
|
||||
|
||||
func Unicode(args []Result) Result {
|
||||
if len(args) != 1 {
|
||||
return MakeErrorResult("UNICODE requires a single string argument")
|
||||
}
|
||||
s := args[0].AsString()
|
||||
if s.Type != ResultTypeString {
|
||||
return MakeErrorResult("UNICODE requires a single string argument")
|
||||
}
|
||||
// Zero length string returns an error
|
||||
if len(s.ValueString) == 0 {
|
||||
return MakeErrorResult("UNICODE requires a non-zero length argument")
|
||||
}
|
||||
|
||||
return MakeNumberResult(float64(s.ValueString[0]))
|
||||
}
|
||||
|
||||
// Concatenate is an implementation of the Excel CONCATENATE() function.
|
||||
func Concatenate(args []Result) Result {
|
||||
buf := bytes.Buffer{}
|
||||
|
@ -44,6 +44,7 @@ func (r Range) Reference(ctx Context, ev Evaluator) Reference {
|
||||
|
||||
// TODO: move these somewhere to remove duplication
|
||||
func ParseCellReference(s string) (col string, row uint32, err error) {
|
||||
s = strings.Replace(s, "$", "", -1)
|
||||
split := -1
|
||||
lfor:
|
||||
for i := 0; i < len(s); i++ {
|
||||
@ -108,7 +109,8 @@ func resultFromCellRange(ctx Context, ev Evaluator, from, to string) Result {
|
||||
for r := fr; r <= tr; r++ {
|
||||
args := []Result{}
|
||||
for c := bc; c <= ec; c++ {
|
||||
args = append(args, ctx.Cell(fmt.Sprintf("%s%d", IndexToColumn(c), r), ev))
|
||||
res := ctx.Cell(fmt.Sprintf("%s%d", IndexToColumn(c), r), ev)
|
||||
args = append(args, res)
|
||||
}
|
||||
arr = append(arr, args)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
// ParseCellReference parses a cell reference of the form 'A10' and splits it
|
||||
// into column/row segments.
|
||||
func ParseCellReference(s string) (col string, row uint32, err error) {
|
||||
s = strings.Replace(s, "$", "", -1)
|
||||
split := -1
|
||||
lfor:
|
||||
for i := 0; i < len(s); i++ {
|
||||
|
Loading…
x
Reference in New Issue
Block a user