CSV to Multi-Markdown Tables
One person noticed yesterday’s yak-shaving and liked it, which was all the excuse I needed to shave it some more. But I am good to go for now, though this still is still fairly fragile: you have to select only the table lines, there’s no way to escape a comma if you want it in a particular entry, it won’t catch if there are different number of items on each line, etc.
Here is the downloadable workflow .
I cleaned up the code in ways that were useful learning exercises for me and added support for >, <, = as separator indicators
so this:
one, two and a half, three and a quarter
four, five, six
still outputs to this:
| one | two and a half | three and a quarter |
| :---: | :---: | :---: |
| four | five | six |
but now this:
one, two and a half, three and a quarter
>, =, <
four, five, six
outputs this:
| one | two and a half | three and a quarter |
| ----: | :---: | :---- |
| four | five | six |
Swift 3.0 code below (still vaguely embarrassed to share it):
#!/usr/bin/swift
import Foundation
let separators: [Character: String] = ["=": ":---:", ">": "----:", "<": ":----"]
let separatorSet = CharacterSet(charactersIn: "><=, ")
func titleAndEntriesFrom(string: String) -> (String, String?, [String])? {
var lines = string.components(separatedBy: "\n")
guard lines.count > 1, let titleLine = lines.first else {
print("need more than one line ->")
return nil
}
lines.removeFirst()
let separatorMarkdown: String?
if let second = lines.first where CharacterSet(charactersIn: second).isSubset(of: separatorSet) {
separatorMarkdown = separatorFrom(line: second)
lines.removeFirst()
} else {
separatorMarkdown = nil
}
return (titleLine, separatorMarkdown, lines)
}
func mdTableFrom(components: (String, String?, [String])) -> String? {
let titleMarkdown = markdownFrom(line: components.0)
let titleEntries = components.0.components(separatedBy: ",")
let separatorMarkdown = components.1 ?? titleEntries.reduce("\n| "){prev, sep in "\(prev) :---: | "}
let bodyMarkdown = components.2.reduce(""){prev, line in "\(prev) \(markdownFrom(line: line))"}
return titleMarkdown + separatorMarkdown + bodyMarkdown
}
func separatorFrom(line: String) -> String {
let entries = line.components(separatedBy: ",")
let things = entries.flatMap({$0.trimmingCharacters(in: CharacterSet.whitespaces).characters.first})
let markdown = things.reduce("\n|"){prev, entry in "\(prev) \(separators[entry] ?? ":xxx:") |"}
return markdown
}
func markdownFrom(line: String) -> String {
guard line.characters.count > 0 else {
return "\n"
}
let entries = line.components(separatedBy: ",")
return entries.reduce("\n| "){prev, entry in "\(prev) \(entry.trimmingCharacters(in: CharacterSet.whitespaces)) |"}
}
var string = ""
while let thing = readLine(strippingNewline: false) {
string += thing
}
if let titleAndBody = titleAndEntriesFrom(string: string), output = mdTableFrom(components: titleAndBody) {
print(output)
} else {
print(string)
}