From 7e998cde5356f3a8e9a1e256420dc9b61dc2b496 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 23 Aug 2026 13:33:00 +0200 Subject: [PATCH] feat(core): add cell address parsing and column labels --- lib/src/address.dart | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 lib/src/address.dart diff --git a/lib/src/address.dart b/lib/src/address.dart new file mode 100644 index 0000000..fca6dac --- /dev/null +++ b/lib/src/address.dart @@ -0,0 +1,64 @@ +final RegExp _addressPattern = RegExp(r'^\$?([A-Za-z]+)\$?([0-9]+)$'); + +int columnIndex(String letters) { + var index = 0; + for (final unit in letters.toUpperCase().codeUnits) { + index = index * 26 + (unit - 0x41 + 1); + } + return index - 1; +} + +String columnLabel(int index) { + var remaining = index + 1; + final units = []; + while (remaining > 0) { + final position = (remaining - 1) % 26; + units.add(0x41 + position); + remaining = (remaining - 1) ~/ 26; + } + return String.fromCharCodes(units.reversed); +} + +class CellAddress { + final int col; + final int row; + + const CellAddress(this.col, this.row); + + factory CellAddress.parse(String reference) { + final match = _addressPattern.firstMatch(reference.trim()); + if (match == null) { + throw FormatException('Invalid cell reference: $reference'); + } + return CellAddress(columnIndex(match.group(1)!), int.parse(match.group(2)!) - 1); + } + + String get label => '${columnLabel(col)}${row + 1}'; + + @override + bool operator ==(Object other) => other is CellAddress && other.col == col && other.row == row; + + @override + int get hashCode => Object.hash(col, row); + + @override + String toString() => label; +} + +List expandRange(CellAddress start, CellAddress end) { + final minCol = start.col < end.col ? start.col : end.col; + final maxCol = start.col > end.col ? start.col : end.col; + final minRow = start.row < end.row ? start.row : end.row; + final maxRow = start.row > end.row ? start.row : end.row; + final cells = []; + for (var row = minRow; row <= maxRow; row++) { + for (var col = minCol; col <= maxCol; col++) { + cells.add(CellAddress(col, row)); + } + } + return cells; +} + +int rangeRowCount(CellAddress start, CellAddress end) => (start.row - end.row).abs() + 1; + +int rangeColCount(CellAddress start, CellAddress end) => (start.col - end.col).abs() + 1;