1
0
mirror of https://github.com/anthonyaxenov/csv2md.git synced 2024-11-26 07:04:57 +00:00

Merge pull request #2 from anthonyaxenov/develop

New v1.2.0: tsv support
This commit is contained in:
Anthony Axenov 2022-02-23 12:29:08 +08:00 committed by GitHub
commit 60b2f676bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 73 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
/bin /bin
# /.vscode # /.vscode
*.csv *.csv
*.tsv
*.md *.md
!example.csv !example.csv

19
.vscode/launch.json vendored
View File

@ -9,10 +9,21 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "main.go" "program": "main.go",
// "args": [ "args": [
// "example.csv", "-f=example.csv",
// ] ]
},
{
"name": "Debug csv2md (tsv)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "main.go",
"args": [
"-t",
"-f=example.tsv",
]
} }
] ]
} }

View File

@ -1,37 +1,63 @@
# csv2md # csv2md
Stupidly simple tool to convert csv-file to [markdown](https://spec-md.com/) table. Stupidly simple tool to convert csv/tsv to [markdown](https://spec-md.com/) table.
Outputs result in stdout. Outputs result in stdout.
## Usage ## Usage
```shell ```shell
csv2md (-h|-help|--help|help) # to get this help csv2md [-help|--help] [-t] [-f <FILE>]
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
...anything is possible with redirection and piping
``` ```
> **IMPORTANT:** Available arguments:
> * input must be valid csv * `-help` or `--help` - get help
> * whitespaces allowed only between double-quotes * `-f=<FILE>` or `-f <FILE>` - convert specified `FILE`
* `-t` - convert input as tsv
Examples can be found here: https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html Available `FILE` formats:
* csv (default);
* tsv (with `-t` argument).
Path to `FILE` may be presented as:
* absolute path;
* path relative to current working directory;
* path relative to user home directory (~).
Also if `PATH` contains whitespaces then you should double-quote it.
To save result as separate file you can use piping.
> **IMPORTANT:**
> 1. Input data must be valid csv/tsv
> 2. Whitespaces allowed only between double-quotes
> 3. Due to markdown spec first line of result table will always be presented as header.
> So if your raw data hasn't one you'll should add it before conversion or edit later in ready md.
### Examples
```
csv2md - paste or type csv to stdin and then
press Ctrl+D to view result in stdout
csv2md -t > example.md - paste or type tsv to stdin and then
press Ctrl+D to write result in new file
csv2md -f example.csv - convert csv from file and view result in stdout
csv2md -t < example.tsv - convert tsv from stdin and view result in stdout
csv2md -t < example.tsv > example.md - convert tsv from stdin and write result in new file
cat example.csv | csv2md - convert csv from stdin and view result in stdout
csv2md -t -f=example.tsv > example.md - convert tsv from file and write result in new file
csv2md -f example.csv | less - convert csv from file and view result in stdout using pager
...anything is possible with redirection and piping, e.g. grep, sed, awk, etc.
```
You can generate some examples here: [csv](https://onlinerandomtools.com/generate-random-csv), [tsv](https://onlinerandomtools.com/generate-random-tsv)
## Compilation ## Compilation
1) [Install go](https://go.dev/learn/). 1) [Install go](https://go.dev/learn/).
2) Download this repo via zip or `git clone`. 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. 3) Run `make help` to get help about compilation or `go run . [ARGS...]` to build and run temporary binary.
## License ## License

6
example.tsv Normal file
View File

@ -0,0 +1,6 @@
impossible political hand larger upward during
shade tip opinion star keep aside
wrong heat line pool song just
she slowly gain snow ourselves six
race thrown get yard nearest swam
though than teacher away dirt escape
1 impossible political hand larger upward during
2 shade tip opinion star keep aside
3 wrong heat line pool song just
4 she slowly gain snow ourselves six
5 race thrown get yard nearest swam
6 though than teacher away dirt escape

107
main.go
View File

@ -11,47 +11,40 @@ import (
"strings" "strings"
) )
const VERSION = "1.1.0" const VERSION = "1.2.0"
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
switch len(os.Args) { filepath := flag.String("f", "", "File path")
case 1: // first we read data from stdin and then convert it is_help := flag.Bool("help", false, "Get help")
data, err := readRawCsv() as_tsv := flag.Bool("t", false, "Parse as tsv")
if err != nil { flag.Parse()
log.Fatal(err)
}
print(data)
case 2: // but if 2nd arg is present if *is_help {
// probably user wants to get help usage(os.Stdout)
help1 := flag.Bool("h", false, "Get help") os.Exit(0)
help2 := flag.Bool("help", false, "Get help") }
flag.Parse()
if os.Args[1] == "help" || *help1 || *help2 {
usage(os.Stdout)
os.Exit(0)
}
// ...or to convert data from file if *filepath == "" {
src, err := ExpandPath(os.Args[1]) data, err := readRawCsv(*as_tsv)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if _, err := os.Stat(src); err != nil { print(data)
log.Fatal(err) } else {
} src, err := ExpandPath(*filepath)
if err != nil {
log.Fatal(err)
}
if _, err := os.Stat(src); err != nil {
log.Fatal(err)
}
data, err := readCsvFile(src) data, err := readCsvFile(src, *as_tsv)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
print(data) print(data)
// otherwise let's show usage help and exit (probably inaccessible code, but anyway)
default:
usage(os.Stdout)
os.Exit(0)
} }
} }
@ -77,7 +70,7 @@ func ExpandPath(path string) (string, error) {
} }
// readRawCsv read data from file // readRawCsv read data from file
func readCsvFile(filePath string) ([][]string, error) { func readCsvFile(filePath string, as_tsv bool) ([][]string, error) {
f, err := os.Open(filePath) f, err := os.Open(filePath)
if err != nil { if err != nil {
return nil, errors.New("Failed to open file '" + filePath + "': " + err.Error()) return nil, errors.New("Failed to open file '" + filePath + "': " + err.Error())
@ -85,21 +78,30 @@ func readCsvFile(filePath string) ([][]string, error) {
defer f.Close() defer f.Close()
csvReader := csv.NewReader(f) csvReader := csv.NewReader(f)
if as_tsv {
csvReader.Comma = '\t'
}
records, err := csvReader.ReadAll() records, err := csvReader.ReadAll()
if err != nil { if err != nil {
return nil, errors.New("Failed to parse CSV from file '" + filePath + "': " + err.Error()) return nil, errors.New("Failed to parse file '" + filePath + "': " + err.Error())
} }
return records, nil return records, nil
} }
// readRawCsv read data from stdin // readRawCsv read data from stdin
func readRawCsv() ([][]string, error) { func readRawCsv(as_tsv bool) ([][]string, error) {
csvReader := csv.NewReader(os.Stdin) csvReader := csv.NewReader(os.Stdin)
if as_tsv {
csvReader.Comma = '\t'
}
records, err := csvReader.ReadAll() records, err := csvReader.ReadAll()
if err != nil { if err != nil {
return nil, errors.New("Failed to parse CSV from stdin: " + err.Error()) return nil, errors.New("Failed to parse input from stdin: " + err.Error())
} }
return records, nil return records, nil
} }
@ -127,20 +129,25 @@ func convert(records [][]string) []string {
func usage(writer *os.File) { func usage(writer *os.File) {
usage := []string{ usage := []string{
"csv2md v" + VERSION, "csv2md v" + VERSION,
"Anthony Axenov (c) 2022, MIT license", "Anthony Axenov (c) 2022, MIT License",
"https://github.com/anthonyaxenov/csv2md", "https://github.com/anthonyaxenov/csv2md",
"", "",
"Usage:", "Usage:",
"\tcsv2md (-h|-help|--help|help) # to get this help", "\tcsv2md [-help|--help] [-t] [-f <FILE>]",
"\tcsv2md example.csv # convert data from file and write result in stdout", "",
"\tcsv2md < example.csv # convert data from stdin and write result in stdout", "Available arguments:",
"\tcat example.csv | csv2md # convert data from stdin and write result in stdout", "\t-help|--help - get this help",
"\tcsv2md example.csv > example.md # convert data from file and write result in new file", "\t-f=<FILE>|-f <FILE> - convert specified FILE",
"\tcsv2md example.csv | less # convert data from file and write result in stdout using pager", "\t-t - convert input as TSV",
"\tcsv2md # paste or type data to stdin by hands", "",
"\t # press Ctrl+D to view result in stdout", "FILE formats supported:",
"\tcsv2md > example.md # paste or type data to stdin by hands", "\t- csv (default)",
"\t # press Ctrl+D to write result in new file", "\t- tsv (with -t flag)",
"",
"Path to FILE may be presented as:",
"\t- absolute",
"\t- relative to current working directory",
"\t- relative to user home directory (~)",
} }
for _, str := range usage { for _, str := range usage {
fmt.Fprintln(writer, str) fmt.Fprintln(writer, str)