@@ -21,6 +21,8 @@ import (
21
21
"strings"
22
22
"time"
23
23
"unicode/utf8"
24
+
25
+ "github.com/xuri/efp"
24
26
)
25
27
26
28
// CellType is the type of cell value type.
@@ -1640,44 +1642,16 @@ func isOverlap(rect1, rect2 []int) bool {
1640
1642
1641
1643
// parseSharedFormula generate dynamic part of shared formula for target cell
1642
1644
// by given column and rows distance and origin shared formula.
1643
- func parseSharedFormula (dCol , dRow int , orig []byte ) (res string , start int ) {
1644
- var (
1645
- end int
1646
- stringLiteral bool
1647
- )
1648
- for end = 0 ; end < len (orig ); end ++ {
1649
- c := orig [end ]
1650
- if c == '"' {
1651
- stringLiteral = ! stringLiteral
1652
- }
1653
- if stringLiteral {
1654
- continue // Skip characters in quotes
1655
- }
1656
- if c >= 'A' && c <= 'Z' || c == '$' {
1657
- res += string (orig [start :end ])
1658
- start = end
1659
- end ++
1660
- foundNum := false
1661
- for ; end < len (orig ); end ++ {
1662
- idc := orig [end ]
1663
- if idc >= '0' && idc <= '9' || idc == '$' {
1664
- foundNum = true
1665
- } else if idc >= 'A' && idc <= 'Z' {
1666
- if foundNum {
1667
- break
1668
- }
1669
- } else {
1670
- break
1671
- }
1672
- }
1673
- if foundNum {
1674
- cellID := string (orig [start :end ])
1675
- res += shiftCell (cellID , dCol , dRow )
1676
- start = end
1677
- }
1645
+ func parseSharedFormula (dCol , dRow int , orig string ) string {
1646
+ ps := efp .ExcelParser ()
1647
+ tokens := ps .Parse (string (orig ))
1648
+ for i := 0 ; i < len (tokens ); i ++ {
1649
+ token := tokens [i ]
1650
+ if token .TType == efp .TokenTypeOperand && token .TSubType == efp .TokenSubTypeRange {
1651
+ tokens [i ].TValue = shiftCell (token .TValue , dCol , dRow )
1678
1652
}
1679
1653
}
1680
- return
1654
+ return ps . Render ()
1681
1655
}
1682
1656
1683
1657
// getSharedFormula find a cell contains the same formula as another cell,
@@ -1698,12 +1672,7 @@ func getSharedFormula(ws *xlsxWorksheet, si int, cell string) string {
1698
1672
sharedCol , sharedRow , _ := CellNameToCoordinates (c .R )
1699
1673
dCol := col - sharedCol
1700
1674
dRow := row - sharedRow
1701
- orig := []byte (c .F .Content )
1702
- res , start := parseSharedFormula (dCol , dRow , orig )
1703
- if start < len (orig ) {
1704
- res += string (orig [start :])
1705
- }
1706
- return res
1675
+ return parseSharedFormula (dCol , dRow , c .F .Content )
1707
1676
}
1708
1677
}
1709
1678
}
@@ -1712,21 +1681,39 @@ func getSharedFormula(ws *xlsxWorksheet, si int, cell string) string {
1712
1681
1713
1682
// shiftCell returns the cell shifted according to dCol and dRow taking into
1714
1683
// consideration absolute references with dollar sign ($)
1715
- func shiftCell (cellID string , dCol , dRow int ) string {
1716
- fCol , fRow , _ := CellNameToCoordinates (cellID )
1717
- signCol , signRow := "" , ""
1718
- if strings .Index (cellID , "$" ) == 0 {
1719
- signCol = "$"
1720
- } else {
1721
- // Shift column
1722
- fCol += dCol
1723
- }
1724
- if strings .LastIndex (cellID , "$" ) > 0 {
1725
- signRow = "$"
1726
- } else {
1727
- // Shift row
1728
- fRow += dRow
1684
+ func shiftCell (val string , dCol , dRow int ) string {
1685
+ parts := strings .Split (val , ":" )
1686
+ for j := 0 ; j < len (parts ); j ++ {
1687
+ cell := parts [j ]
1688
+ trimmedCellName := strings .ReplaceAll (cell , "$" , "" )
1689
+ c , r , err := CellNameToCoordinates (trimmedCellName )
1690
+ if err == nil {
1691
+ absCol := strings .Index (cell , "$" ) == 0
1692
+ absRow := strings .LastIndex (cell , "$" ) > 0
1693
+ if ! absCol && ! absRow {
1694
+ parts [j ], _ = CoordinatesToCellName (c + dCol , r + dRow )
1695
+ }
1696
+ if ! absCol && absRow {
1697
+ colName , _ := ColumnNumberToName (c + dCol )
1698
+ parts [j ] = colName + "$" + strconv .Itoa (r )
1699
+ }
1700
+ if absCol && ! absRow {
1701
+ colName , _ := ColumnNumberToName (c )
1702
+ parts [j ] = "$" + colName + strconv .Itoa (r + dRow )
1703
+ }
1704
+ continue
1705
+ }
1706
+ // Cell reference is a column name
1707
+ c , err = ColumnNameToNumber (trimmedCellName )
1708
+ if err == nil && ! strings .HasPrefix (cell , "$" ) {
1709
+ parts [j ], _ = ColumnNumberToName (c + dCol )
1710
+ continue
1711
+ }
1712
+ // Cell reference is a row number
1713
+ r , err = strconv .Atoi (trimmedCellName )
1714
+ if err == nil && ! strings .HasPrefix (cell , "$" ) {
1715
+ parts [j ] = strconv .Itoa (r + dRow )
1716
+ }
1729
1717
}
1730
- colName , _ := ColumnNumberToName (fCol )
1731
- return signCol + colName + signRow + strconv .Itoa (fRow )
1718
+ return strings .Join (parts , ":" )
1732
1719
}
0 commit comments