oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1import Foundation
2
3struct Coordinate: Hashable, Sendable {
4 let r: Int
5 let c: Int
6 var ref: String {
7 var c = c
8 var label = ""
9 repeat {
10 label = String(UnicodeScalar(65 + c % 26)!) + label
11 c = c / 26 - 1
12 } while c >= 0
13 return label + String(r + 1)
14 }
15 static func parse(_ text: String) -> Coordinate? {
16 let text = text.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
17 let letters = text.prefix { $0.isASCII && $0.isLetter }
18 guard !letters.isEmpty, letters.count <= 3, let row = Int(text.dropFirst(letters.count)),
19 row > 0, row <= 5000
20 else { return nil }
21 let col = letters.utf8.reduce(0) { $0 * 26 + Int($1) - 64 }
22 guard col <= 2000 else { return nil }
23 return Coordinate(r: row - 1, c: col - 1)
24 }
25}
26struct CellRange: Equatable, Sendable {
27 let start: Coordinate
28 let end: Coordinate
29 init(_ a: Coordinate, _ b: Coordinate) {
30 start = Coordinate(r: min(a.r, b.r), c: min(a.c, b.c))
31 end = Coordinate(r: max(a.r, b.r), c: max(a.c, b.c))
32 }
33 static func parse(_ text: String) -> CellRange? {
34 let parts = text.split(separator: ":", omittingEmptySubsequences: false)
35 guard (1...2).contains(parts.count), let a = Coordinate.parse(String(parts[0])),
36 let b = Coordinate.parse(String(parts.last!))
37 else { return nil }
38 return CellRange(a, b)
39 }
40 var coordinates: [Coordinate] {
41 (start.r...end.r).flatMap { r in (start.c...end.c).map { Coordinate(r: r, c: $0) } }
42 }
43 var count: Int { (end.r - start.r + 1) * (end.c - start.c + 1) }
44 func contains(_ p: Coordinate) -> Bool {
45 (start.r...end.r).contains(p.r) && (start.c...end.c).contains(p.c)
46 }
47}
48