mirror of
https://github.com/anthonyaxenov/csv2md.git
synced 2024-12-26 16:08:31 +00:00
commit
c7fd26e7b4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/bin
|
||||
# /.vscode
|
||||
*.csv
|
||||
*.md
|
||||
!example.csv
|
||||
|
28
.vscode/launch.json
vendored
28
.vscode/launch.json
vendored
@ -2,19 +2,17 @@
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileBasename}",
|
||||
"args": [
|
||||
"example.csv",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug csv2md",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "main.go"
|
||||
// "args": [
|
||||
// "example.csv",
|
||||
// ]
|
||||
}
|
||||
]
|
||||
}
|
33
README.md
33
README.md
@ -4,20 +4,35 @@ Stupidly simple tool to convert csv-file to [markdown](https://spec-md.com/) tab
|
||||
|
||||
Outputs result in stdout.
|
||||
|
||||
Building:
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
make help
|
||||
```
|
||||
csv2md (-h|-help|--help|help) # to get this help
|
||||
csv2md example.csv # convert data from file and write result in stdout
|
||||
csv2md < example.csv # convert data from stdin and write result in stdout
|
||||
cat example.csv | csv2md # convert data from stdin and write result in stdout
|
||||
csv2md example.csv > example.md # convert data from file and write result in new file
|
||||
csv2md example.csv | less # convert data from file and write result in stdout using pager
|
||||
csv2md # paste or type data to stdin by hands
|
||||
# press Ctrl+D to view result in stdout
|
||||
csv2md > example.md # paste or type data to stdin by hands
|
||||
# press Ctrl+D to write result in new file
|
||||
|
||||
Usage:
|
||||
|
||||
```shell
|
||||
csv2md example.csv > example.md # makes new file
|
||||
csv2md example.csv | less # view result using *pager*
|
||||
...anything is possible with redirection and piping
|
||||
```
|
||||
|
||||
> **IMPORTANT:** input must be valid csv and whitespaces are allowed only between double-quotes.
|
||||
> **IMPORTANT:**
|
||||
> * input must be valid csv
|
||||
> * whitespaces allowed only between double-quotes
|
||||
|
||||
Examples can be found here: https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html
|
||||
|
||||
## Compilation
|
||||
|
||||
1) [Install go](https://go.dev/learn/).
|
||||
2) Download this repo via zip or `git clone`.
|
||||
3) Run `make help` to get help or `go run . <csv_path>` to build and run temporary binary.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
64
example.csv
64
example.csv
@ -1,14 +1,50 @@
|
||||
"Month","1958","1959","1960"
|
||||
"JAN",340,360,417
|
||||
"FEB",318,342,391
|
||||
"MAR",362,406,419
|
||||
"APR",348,396,461
|
||||
"MAY",363,420,472
|
||||
"JUN",435,472,535
|
||||
"JUL",491,548,622
|
||||
"AUG",505,559,606
|
||||
"SEP",404,463,508
|
||||
"OCT",359,407,461
|
||||
"NOV",310,362,390
|
||||
"DEC",337,405,432
|
||||
|
||||
"Name","Team","Position","Height(inches)","Weight(lbs)","Age"
|
||||
"Adam Donachie","BAL","Catcher",74,180,22.99
|
||||
"Paul Bako","BAL","Catcher",74,215,34.69
|
||||
"Ramon Hernandez","BAL","Catcher",72,210,30.78
|
||||
"Kevin Millar","BAL","First Baseman",72,210,35.43
|
||||
"Chris Gomez","BAL","First Baseman",73,188,35.71
|
||||
"Brian Roberts","BAL","Second Baseman",69,176,29.39
|
||||
"Miguel Tejada","BAL","Shortstop",69,209,30.77
|
||||
"Melvin Mora","BAL","Third Baseman",71,200,35.07
|
||||
"Aubrey Huff","BAL","Third Baseman",76,231,30.19
|
||||
"Adam Stern","BAL","Outfielder",71,180,27.05
|
||||
"Jeff Fiorentino","BAL","Outfielder",73,188,23.88
|
||||
"Freddie Bynum","BAL","Outfielder",73,180,26.96
|
||||
"Nick Markakis","BAL","Outfielder",74,185,23.29
|
||||
"Brandon Fahey","BAL","Outfielder",74,160,26.11
|
||||
"Corey Patterson","BAL","Outfielder",69,180,27.55
|
||||
"Jay Payton","BAL","Outfielder",70,185,34.27
|
||||
"Jay Gibbons","BAL","Designated Hitter",72,197,30
|
||||
"Erik Bedard","BAL","Starting Pitcher",73,189,27.99
|
||||
"Hayden Penn","BAL","Starting Pitcher",75,185,22.38
|
||||
"Adam Loewen","BAL","Starting Pitcher",78,219,22.89
|
||||
"Daniel Cabrera","BAL","Starting Pitcher",79,230,25.76
|
||||
"Steve Trachsel","BAL","Starting Pitcher",76,205,36.33
|
||||
"Jaret Wright","BAL","Starting Pitcher",74,230,31.17
|
||||
"Kris Benson","BAL","Starting Pitcher",76,195,32.31
|
||||
"Scott Williamson","BAL","Relief Pitcher",72,180,31.03
|
||||
"John Parrish","BAL","Relief Pitcher",71,192,29.26
|
||||
"Danys Baez","BAL","Relief Pitcher",75,225,29.47
|
||||
"Chad Bradford","BAL","Relief Pitcher",77,203,32.46
|
||||
"Jamie Walker","BAL","Relief Pitcher",74,195,35.67
|
||||
"Brian Burres","BAL","Relief Pitcher",73,182,25.89
|
||||
"Kurt Birkins","BAL","Relief Pitcher",74,188,26.55
|
||||
"James Hoey","BAL","Relief Pitcher",78,200,24.17
|
||||
"Sendy Rleal","BAL","Relief Pitcher",73,180,26.69
|
||||
"Chris Ray","BAL","Relief Pitcher",75,200,25.13
|
||||
"Jeremy Guthrie","BAL","Relief Pitcher",73,200,27.9
|
||||
"A.J. Pierzynski","CWS","Catcher",75,245,30.17
|
||||
"Toby Hall","CWS","Catcher",75,240,31.36
|
||||
"Paul Konerko","CWS","First Baseman",74,215,30.99
|
||||
"Tadahito Iguchi","CWS","Second Baseman",69,185,32.24
|
||||
"Juan Uribe","CWS","Shortstop",71,175,27.61
|
||||
"Alex Cintron","CWS","Shortstop",74,199,28.2
|
||||
"Joe Crede","CWS","Third Baseman",73,200,28.85
|
||||
"Josh Fields","CWS","Third Baseman",73,215,24.21
|
||||
"Ryan Sweeney","CWS","Outfielder",76,200,22.02
|
||||
"Brian N. Anderson","CWS","Outfielder",74,205,24.97
|
||||
"Luis Terrero","CWS","Outfielder",74,206,26.78
|
||||
"Pablo Ozuna","CWS","Outfielder",70,186,32.51
|
||||
"Scott Podsednik","CWS","Outfielder",72,188,30.95
|
||||
"Jermaine Dye","CWS","Outfielder",77,220,33.09
|
||||
|
|
111
main.go
111
main.go
@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
@ -9,33 +11,62 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const VERSION = "1.0.0"
|
||||
const VERSION = "1.1.0"
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
log.SetFlags(0)
|
||||
switch len(os.Args) {
|
||||
case 1: // first we read data from stdin and then convert it
|
||||
data, err := readRawCsv()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
print(data)
|
||||
|
||||
src, err := ExpandPath(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := os.Stat(src); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
case 2: // but if 2nd arg is present
|
||||
// probably user wants to get help
|
||||
help1 := flag.Bool("h", false, "Get help")
|
||||
help2 := flag.Bool("help", false, "Get help")
|
||||
flag.Parse()
|
||||
if os.Args[1] == "help" || *help1 || *help2 {
|
||||
usage(os.Stdout)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
result := convert(readCsv(src))
|
||||
// ...or to convert data from file
|
||||
src, err := ExpandPath(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(src); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := readCsvFile(src)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
print(data)
|
||||
|
||||
// otherwise let's show usage help and exit (probably inaccessible code, but anyway)
|
||||
default:
|
||||
usage(os.Stdout)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// print write converted data to stdout
|
||||
func print(data [][]string) {
|
||||
if len(data) == 0 {
|
||||
usage(os.Stderr)
|
||||
}
|
||||
result := convert(data)
|
||||
for _, row := range result {
|
||||
fmt.Println(row)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, "csv2md v" + VERSION)
|
||||
fmt.Fprintln(os.Stderr, "Usage: csv2md data.csv > data.md")
|
||||
}
|
||||
|
||||
// ExpandPath return absolute path to file replacing ~ to user's home folder
|
||||
func ExpandPath(path string) (string, error) {
|
||||
homepath, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
@ -45,22 +76,34 @@ func ExpandPath(path string) (string, error) {
|
||||
return newpath, err
|
||||
}
|
||||
|
||||
func readCsv(filePath string) [][]string {
|
||||
// readRawCsv read data from file
|
||||
func readCsvFile(filePath string) ([][]string, error) {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to read input file " + filePath, err)
|
||||
return nil, errors.New("Failed to open file '" + filePath + "': " + err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
csvReader := csv.NewReader(f)
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to parse file as CSV for " + filePath, err)
|
||||
return nil, errors.New("Failed to parse CSV from file '" + filePath + "': " + err.Error())
|
||||
}
|
||||
|
||||
return records
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// readRawCsv read data from stdin
|
||||
func readRawCsv() ([][]string, error) {
|
||||
csvReader := csv.NewReader(os.Stdin)
|
||||
records, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to parse CSV from stdin: " + err.Error())
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// convert format data from file or stdin as markdown
|
||||
func convert(records [][]string) []string {
|
||||
var result []string
|
||||
for idx, row := range records {
|
||||
@ -79,3 +122,27 @@ func convert(records [][]string) []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// usage print help into writer
|
||||
func usage(writer *os.File) {
|
||||
usage := []string{
|
||||
"csv2md v" + VERSION,
|
||||
"Anthony Axenov (c) 2022, MIT license",
|
||||
"https://github.com/anthonyaxenov/csv2md",
|
||||
"",
|
||||
"Usage:",
|
||||
"\tcsv2md (-h|-help|--help|help) # to get this help",
|
||||
"\tcsv2md example.csv # convert data from file and write result in stdout",
|
||||
"\tcsv2md < example.csv # convert data from stdin and write result in stdout",
|
||||
"\tcat example.csv | csv2md # convert data from stdin and write result in stdout",
|
||||
"\tcsv2md example.csv > example.md # convert data from file and write result in new file",
|
||||
"\tcsv2md example.csv | less # convert data from file and write result in stdout using pager",
|
||||
"\tcsv2md # paste or type data to stdin by hands",
|
||||
"\t # press Ctrl+D to view result in stdout",
|
||||
"\tcsv2md > example.md # paste or type data to stdin by hands",
|
||||
"\t # press Ctrl+D to write result in new file",
|
||||
}
|
||||
for _, str := range usage {
|
||||
fmt.Fprintln(writer, str)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user