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
3// Quoting matches spreadsheets: tabs/newlines/quotes round-trip as cell content.
4enum TSV {
5 static func encode(_ rows: [[String]]) -> String {
6 rows.map {
7 $0.map { text in
8 text.contains(where: {
9 $0 == "\t" || $0 == "\r" || $0 == "\n" || $0 == "\r\n" || $0 == "\""
10 }) ? "\"" + text.replacingOccurrences(of: "\"", with: "\"\"") + "\"" : text
11 }.joined(separator: "\t")
12 }.joined(separator: "\n")
13 }
14 static func decode(_ text: String) -> [[String]] {
15 let chars = Array(text)
16 var rows: [[String]] = []
17 var row: [String] = []
18 var cell = ""
19 var quoted = false
20 var i = 0
21 while i < chars.count {
22 let ch = chars[i]
23 if ch == "\"" {
24 if quoted && i + 1 < chars.count && chars[i + 1] == "\"" {
25 cell.append(ch)
26 i += 1
27 } else if quoted || cell.isEmpty {
28 quoted.toggle()
29 } else {
30 cell.append(ch)
31 }
32 } else if !quoted && ch == "\t" {
33 row.append(cell)
34 cell = ""
35 } else if !quoted && (ch == "\n" || ch == "\r\n" || ch == "\r") {
36 row.append(cell)
37 rows.append(row)
38 row = []
39 cell = ""
40 } else {
41 cell.append(ch)
42 }
43 i += 1
44 }
45 row.append(cell)
46 rows.append(row)
47 if rows.last == [""] && (text.last == "\n" || text.last == "\r\n" || text.last == "\r") {
48 rows.removeLast()
49 }
50 return rows
51 }
52}
53