mirror of
https://github.com/anthonyaxenov/csv2md.git
synced 2024-12-27 08:28:32 +00:00
Merge pull request #2 from anthonyaxenov/develop
New v1.2.0: tsv support
This commit is contained in:
commit
60b2f676bd
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/bin
|
||||
# /.vscode
|
||||
*.csv
|
||||
*.tsv
|
||||
*.md
|
||||
!example.csv
|
||||
|
21
.vscode/launch.json
vendored
21
.vscode/launch.json
vendored
@ -9,10 +9,21 @@
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "main.go"
|
||||
// "args": [
|
||||
// "example.csv",
|
||||
// ]
|
||||
"program": "main.go",
|
||||
"args": [
|
||||
"-f=example.csv",
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Debug csv2md (tsv)",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "main.go",
|
||||
"args": [
|
||||
"-t",
|
||||
"-f=example.tsv",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
62
README.md
62
README.md
@ -1,37 +1,63 @@
|
||||
# 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.
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
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
|
||||
|
||||
...anything is possible with redirection and piping
|
||||
csv2md [-help|--help] [-t] [-f <FILE>]
|
||||
```
|
||||
|
||||
> **IMPORTANT:**
|
||||
> * input must be valid csv
|
||||
> * whitespaces allowed only between double-quotes
|
||||
Available arguments:
|
||||
* `-help` or `--help` - get help
|
||||
* `-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
|
||||
|
||||
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.
|
||||
3) Run `make help` to get help about compilation or `go run . [ARGS...]` to build and run temporary binary.
|
||||
|
||||
## License
|
||||
|
||||
|
6
example.tsv
Normal file
6
example.tsv
Normal 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
|
|
107
main.go
107
main.go
@ -11,47 +11,40 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const VERSION = "1.1.0"
|
||||
const VERSION = "1.2.0"
|
||||
|
||||
func main() {
|
||||
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)
|
||||
filepath := flag.String("f", "", "File path")
|
||||
is_help := flag.Bool("help", false, "Get help")
|
||||
as_tsv := flag.Bool("t", false, "Parse as tsv")
|
||||
flag.Parse()
|
||||
|
||||
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)
|
||||
}
|
||||
if *is_help {
|
||||
usage(os.Stdout)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// ...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)
|
||||
}
|
||||
if *filepath == "" {
|
||||
data, err := readRawCsv(*as_tsv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
print(data)
|
||||
} 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)
|
||||
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)
|
||||
data, err := readCsvFile(src, *as_tsv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
print(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +70,7 @@ func ExpandPath(path string) (string, error) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, errors.New("Failed to open file '" + filePath + "': " + err.Error())
|
||||
@ -85,21 +78,30 @@ func readCsvFile(filePath string) ([][]string, error) {
|
||||
defer f.Close()
|
||||
|
||||
csvReader := csv.NewReader(f)
|
||||
if as_tsv {
|
||||
csvReader.Comma = '\t'
|
||||
}
|
||||
|
||||
records, err := csvReader.ReadAll()
|
||||
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
|
||||
}
|
||||
|
||||
// readRawCsv read data from stdin
|
||||
func readRawCsv() ([][]string, error) {
|
||||
func readRawCsv(as_tsv bool) ([][]string, error) {
|
||||
csvReader := csv.NewReader(os.Stdin)
|
||||
if as_tsv {
|
||||
csvReader.Comma = '\t'
|
||||
}
|
||||
|
||||
records, err := csvReader.ReadAll()
|
||||
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
|
||||
}
|
||||
|
||||
@ -127,20 +129,25 @@ func convert(records [][]string) []string {
|
||||
func usage(writer *os.File) {
|
||||
usage := []string{
|
||||
"csv2md v" + VERSION,
|
||||
"Anthony Axenov (c) 2022, MIT license",
|
||||
"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",
|
||||
"\tcsv2md [-help|--help] [-t] [-f <FILE>]",
|
||||
"",
|
||||
"Available arguments:",
|
||||
"\t-help|--help - get this help",
|
||||
"\t-f=<FILE>|-f <FILE> - convert specified FILE",
|
||||
"\t-t - convert input as TSV",
|
||||
"",
|
||||
"FILE formats supported:",
|
||||
"\t- csv (default)",
|
||||
"\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 {
|
||||
fmt.Fprintln(writer, str)
|
||||
|
Loading…
Reference in New Issue
Block a user