Skip to content

Commit

Permalink
New functions cell_name_to_coordinates, column_name_to_number and col…
Browse files Browse the repository at this point in the history
…umn_number_to_name (#4)

- Update unit tests and docs for the function
  • Loading branch information
covv authored Dec 4, 2024
1 parent 9720509 commit cafda31
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 3 deletions.
52 changes: 52 additions & 0 deletions excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,58 @@ def set_sheet_row(
return None if err == "" else Exception(err)


def cell_name_to_coordinates(cell: str) -> Tuple[int, int, Exception | None]:
"""
Converts alphanumeric cell name to [X, Y] coordinates or returns an error.
Args:
cell (str): The cell reference
Returns:
Tuple[int, int, Exception | None]: A tuple containing the column number,
row number, and an Exception if an error occurred, otherwise None.
"""
lib.CellNameToCoordinates.restype = types_go._CellNameToCoordinatesResult
res = lib.CellNameToCoordinates(cell.encode(ENCODE))
err = res.err.decode(ENCODE)
return res.col, res.row, None if err == "" else Exception(err)


def column_name_to_number(name: str) -> Tuple[int, Exception | None]:
"""
Convert Excel sheet column name (case-insensitive) to int. The function
returns an error if column name incorrect.
Args:
name (str): The column name
Returns:
Tuple[int, Exception | None]: A tuple containing the column number and
an Exception if an error occurred, otherwise None.
"""
lib.ColumnNameToNumber.restype = types_go._ColumnNameToNumberResult
res = lib.ColumnNameToNumber(name.encode(ENCODE))
err = res.err.decode(ENCODE)
return res.col, None if err == "" else Exception(err)


def column_number_to_name(num: int) -> Tuple[str, Exception | None]:
"""
Convert the integer to Excel sheet column title.
Args:
num (int): The column number
Returns:
Tuple[str, Exception | None]: A tuple containing the column name and an
Exception if an error occurred, otherwise None.
"""
lib.ColumnNumberToName.restype = types_go._ColumnNumberToNameResult
res = lib.ColumnNumberToName(c_int(num))
err = res.err.decode(ENCODE)
return res.col.decode(ENCODE), None if err == "" else Exception(err)


def coordinates_to_cell_name(
col: int, row: int, *abs: bool
) -> Tuple[str, Exception | None]:
Expand Down
37 changes: 37 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,43 @@ func AddPicture(idx int, sheet, cell, name *C.char, opts *C.struct_GraphicOption
return C.CString(errNil)
}

// CellNameToCoordinates converts alphanumeric cell name to [X, Y] coordinates
// or returns an error.
//
//export CellNameToCoordinates
func CellNameToCoordinates(cell *C.char) C.struct_CellNameToCoordinatesResult {
col, row, err := excelize.CellNameToCoordinates(C.GoString(cell))
if err != nil {
return C.struct_CellNameToCoordinatesResult{col: C.int(col), row: C.int(row), err: C.CString(err.Error())}
}
return C.struct_CellNameToCoordinatesResult{col: C.int(col), row: C.int(row), err: C.CString(errNil)}
}

// ColumnNameToNumber provides a function to convert Excel sheet column name
// (case-insensitive) to int. The function returns an error if column name
// incorrect.
//
//export ColumnNameToNumber
func ColumnNameToNumber(name *C.char) C.struct_CellNameToCoordinatesResult {
col, err := excelize.ColumnNameToNumber(C.GoString(name))
if err != nil {
return C.struct_CellNameToCoordinatesResult{col: C.int(col), err: C.CString(err.Error())}
}
return C.struct_CellNameToCoordinatesResult{col: C.int(col), err: C.CString(errNil)}
}

// ColumnNumberToName provides a function to convert the integer to Excel
// sheet column title.
//
//export ColumnNumberToName
func ColumnNumberToName(num int) C.struct_ColumnNumberToNameResult {
col, err := excelize.ColumnNumberToName(num)
if err != nil {
return C.struct_ColumnNumberToNameResult{col: C.CString(col), err: C.CString(err.Error())}
}
return C.struct_ColumnNumberToNameResult{col: C.CString(col), err: C.CString(errNil)}
}

// CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell name
// or returns an error.
//
Expand Down
38 changes: 38 additions & 0 deletions test_excelize.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,44 @@ def test_add_chart(self):
)
self.assertIsNone(f.save_as("TestAddChart.xlsx"))

def test_cell_name_to_coordinates(self):
col, row, err = excelize.cell_name_to_coordinates("Z3")
self.assertEqual(col, 26)
self.assertEqual(row, 3)
self.assertIsNone(err)

col, row, err = excelize.cell_name_to_coordinates("A")
self.assertEqual(col, -1)
self.assertEqual(row, -1)
self.assertEqual(
err.__str__(),
'cannot convert cell "A" to coordinates: invalid cell name "A"',
)

def test_column_name_to_number(self):
col, err = excelize.column_name_to_number("Z")
self.assertEqual(col, 26)
self.assertIsNone(err)

col, err = excelize.column_name_to_number("-")
self.assertEqual(col, -1)
self.assertEqual(
err.__str__(),
'invalid column name "-"',
)

def test_column_number_to_name(self):
name, err = excelize.column_number_to_name(26)
self.assertEqual(name, "Z")
self.assertIsNone(err)

name, err = excelize.column_number_to_name(0)
self.assertEqual(name, "")
self.assertEqual(
err.__str__(),
"the column number must be greater than or equal to 1 and less than or equal to 16384",
)

def test_add_picture(self):
f = excelize.new_file()
self.assertIsNone(f.add_picture("Sheet1", "A1", "chart.png", None))
Expand Down
16 changes: 16 additions & 0 deletions types_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,22 @@ struct Chart {
int HoleSize;
};

struct CellNameToCoordinatesResult {
int col;
int row;
char* err;
};

struct ColumnNameToNumberResult {
int col;
char* err;
};

struct ColumnNumberToNameResult {
char* col;
char* err;
};

struct CoordinatesToCellNameResult {
char* cell;
char* err;
Expand Down
22 changes: 22 additions & 0 deletions types_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,28 @@ class _Chart(Structure):
]


class _CellNameToCoordinatesResult(Structure):
_fields_ = [
("col", c_int),
("row", c_int),
("err", c_char_p),
]


class _ColumnNameToNumberResult(Structure):
_fields_ = [
("col", c_int),
("err", c_char_p),
]


class _ColumnNumberToNameResult(Structure):
_fields_ = [
("col", c_char_p),
("err", c_char_p),
]


class _CoordinatesToCellNameResult(Structure):
_fields_ = [
("cell", c_char_p),
Expand Down
99 changes: 96 additions & 3 deletions types_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@


class CultureName(IntEnum):
"""
This section defines the currently supported country code types enumeration
for apply number format.
"""

CultureNameUnknown = 0
CultureNameEnUS = 1
CultureNameJaJP = 2
Expand All @@ -23,7 +28,52 @@ class CultureName(IntEnum):
CultureNameZhTW = 5


class CellType(IntEnum):
"""
This section defines the cell value types enumeration.
"""

CellTypeUnset = 0
CellTypeBool = 1
CellTypeDate = 2
CellTypeError = 3
CellTypeFormula = 4
CellTypeInlineString = 5
CellTypeNumber = 6
CellTypeSharedString = 7


class FormControlType(IntEnum):
"""
FormControlType is the type of supported form controls.
"""

FormControlNote = 0
FormControlButton = 1
FormControlOptionButton = 2
FormControlSpinButton = 3
FormControlCheckBox = 4
FormControlGroupBox = 5
FormControlLabel = 6
FormControlScrollBar = 7


class ChartLineType(IntEnum):
"""
ChartLineType defines the currently supported chart line types enumeration.
"""

ChartLineUnset = 0
ChartLineSolid = 1
ChartLineNone = 2
ChartLineAutomatic = 3


class ChartType(IntEnum):
"""
ChartType defines the currently supported chart types enumeration.
"""

Area = 0
AreaStacked = 1
AreaPercentStacked = 2
Expand Down Expand Up @@ -81,6 +131,45 @@ class ChartType(IntEnum):
Bubble3D = 54


class ChartDataLabelPositionType(IntEnum):
"""
ChartDataLabelPositionType is the type of chart data labels position.
"""

ChartDataLabelsPositionUnset = 0
ChartDataLabelsPositionBestFit = 1
ChartDataLabelsPositionBelow = 2
ChartDataLabelsPositionCenter = 3
ChartDataLabelsPositionInsideBase = 4
ChartDataLabelsPositionInsideEnd = 5
ChartDataLabelsPositionLeft = 6
ChartDataLabelsPositionOutsideEnd = 7
ChartDataLabelsPositionRight = 8
ChartDataLabelsPositionAbove = 9


class ChartTickLabelPositionType(IntEnum):
"""
ChartTickLabelPositionType is the type of supported chart tick label
"""

ChartTickLabelNextToAxis = 0
ChartTickLabelHigh = 1
ChartTickLabelLow = 2
ChartTickLabelNone = 3


class PictureInsertType(IntEnum):
"""
PictureInsertType defines the type of the picture has been inserted into the
worksheet.
"""

PictureInsertTypePlaceOverCells = 0
PictureInsertTypePlaceInCell = 1
PictureInsertTypeDISPIMG = 2


@dataclass
class Interface:
type: int = 0
Expand Down Expand Up @@ -210,7 +299,9 @@ class ChartAxis:
major_grid_lines: bool = False
minor_grid_lines: bool = False
major_unit: float = 0
tick_label_position: int = 0
tick_label_position: ChartDataLabelPositionType = (
ChartDataLabelPositionType.ChartDataLabelsPositionUnset
)
tick_label_skip: int = 0
reverse_order: bool = False
secondary: bool = False
Expand Down Expand Up @@ -257,7 +348,7 @@ class ChartMarker:

@dataclass
class ChartLine:
type: int = 0
type: ChartLineType = ChartLineType.ChartLineUnset
smooth: bool = False
width: float = 0

Expand All @@ -271,7 +362,9 @@ class ChartSeries:
fill: Fill = Fill
line: ChartLine = ChartLine
marker: ChartMarker = ChartMarker
data_label_position: int = 0
data_label_position: ChartDataLabelPositionType = (
ChartDataLabelPositionType.ChartDataLabelsPositionUnset
)


@dataclass
Expand Down

0 comments on commit cafda31

Please sign in to comment.