| 1 | module TSV ( |
| 2 | parseTSV, formatTSV |
| 3 | ) where |
| 4 | import Data.List |
| 5 | |
| 6 | -- Simple implementation of tab-separated values with a trailing newline and no |
| 7 | -- quoting support. |
| 8 | |
| 9 | splitList :: Eq a => a -> Bool -> [a] -> [[a]] |
| 10 | splitList delim terminated = |
| 11 | let sl [] | terminated = [] |
| 12 | sl l = case break (== delim) l of |
| 13 | (hh, []) -> [hh] |
| 14 | (hh, {-delim-} _ : t) -> hh : sl t |
| 15 | in sl |
| 16 | |
| 17 | -- We use the Eq only to check the validity... |
| 18 | joinList :: Eq a => a -> Bool -> [[a]] -> [a] |
| 19 | joinList delim terminated l = |
| 20 | if any (any (== delim)) l then error "joinList: item contains delimiter" |
| 21 | else if terminated |
| 22 | then concatMap (++ [delim]) l |
| 23 | else intercalate [delim] l |
| 24 | |
| 25 | type TSV = [[String]] |
| 26 | |
| 27 | formatTSV :: TSV -> String |
| 28 | formatTSV = joinList '\n' True . map (joinList '\t' False) |
| 29 | |
| 30 | parseTSV :: String -> TSV |
| 31 | parseTSV = map (splitList '\t' False) . splitList '\n' True |