Skip to content

Commit

Permalink
Merge pull request #2 from anthonyaxenov/develop
Browse files Browse the repository at this point in the history
New v1.2.0: tsv support
  • Loading branch information
anthonyaxenov authored Feb 23, 2022
2 parents c7fd26e + 13dedba commit 60b2f67
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 72 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/bin
# /.vscode
*.csv
*.tsv
*.md
!example.csv
21 changes: 16 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
}
]
}
}
60 changes: 43 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -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>]
```

Available arguments:
* `-help` or `--help` - get help
* `-f=<FILE>` or `-f <FILE>` - convert specified `FILE`
* `-t` - convert input as tsv

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:**
> * input must be valid csv
> * whitespaces allowed only between double-quotes
> 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.
```

Examples can be found here: https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html
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

Expand Down
6 changes: 6 additions & 0 deletions example.tsv
Original file line number Diff line number Diff line change
@@ -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 changes: 57 additions & 50 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

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)
}
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()

// ...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 *is_help {
usage(os.Stdout)
os.Exit(0)
}

data, err := readCsvFile(src)
if err != nil {
log.Fatal(err)
}
print(data)
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)
}

// 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)
}
}

Expand All @@ -77,29 +70,38 @@ 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())
}
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
}

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 60b2f67

Please sign in to comment.