(text: string)
| 25 | |
| 26 | /** Parse CSV text into a grid of string cells. Blank lines are dropped. */ |
| 27 | export function parseCsv(text: string): string[][] { |
| 28 | const rows: string[][] = [] |
| 29 | let row: string[] = [] |
| 30 | let field = '' |
| 31 | let inQuotes = false |
| 32 | let i = text.charCodeAt(0) === 0xfeff ? 1 : 0 // strip BOM |
| 33 | const n = text.length |
| 34 | |
| 35 | const endField = (): void => { |
| 36 | row.push(field) |
| 37 | field = '' |
| 38 | } |
| 39 | const endRow = (): void => { |
| 40 | endField() |
| 41 | // Drop blank lines (a single empty field). |
| 42 | if (!(row.length === 1 && row[0] === '')) rows.push(row) |
| 43 | row = [] |
| 44 | } |
| 45 | |
| 46 | while (i < n) { |
| 47 | const ch = text[i] |
| 48 | if (inQuotes) { |
| 49 | if (ch === '"') { |
| 50 | if (text[i + 1] === '"') { |
| 51 | field += '"' |
| 52 | i += 2 |
| 53 | continue |
| 54 | } |
| 55 | inQuotes = false |
| 56 | i++ |
| 57 | continue |
| 58 | } |
| 59 | field += ch |
| 60 | i++ |
| 61 | continue |
| 62 | } |
| 63 | if (ch === '"') { |
| 64 | inQuotes = true |
| 65 | i++ |
| 66 | } else if (ch === ',') { |
| 67 | endField() |
| 68 | i++ |
| 69 | } else if (ch === '\r') { |
| 70 | endRow() |
| 71 | i += text[i + 1] === '\n' ? 2 : 1 |
| 72 | } else if (ch === '\n') { |
| 73 | endRow() |
| 74 | i++ |
| 75 | } else { |
| 76 | field += ch |
| 77 | i++ |
| 78 | } |
| 79 | } |
| 80 | // Flush trailing field/row unless the text ended exactly on a row boundary. |
| 81 | if (field !== '' || row.length > 0) endRow() |
| 82 | return rows |
| 83 | } |
| 84 |
no test coverage detected