This commit is contained in:
Bruno F. Fontes 2025-03-30 13:14:15 -03:00
parent 649144b0ac
commit ef06148d49
Signed by: brunofontes
GPG Key ID: 81DC18AF0B4EEE74
5 changed files with 287 additions and 0 deletions

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitea.brunofontes.net/BFT/go-csv-table
go 1.24.1

113
gocsvtable.go Normal file
View File

@ -0,0 +1,113 @@
package gocsvtable
import (
"encoding/csv"
"fmt"
"io"
"os"
)
type GoCSVtable struct {
file *csv.Reader
rows int
data [][]string
Headers map[string]int
Separator rune
Comment rune
lastRow int
// Row is the active CSV row, the data will start at 1
Row int
}
func (gct *GoCSVtable) OpenCSV(filename string) error {
osfile, err := os.Open(filename)
if err != nil {
return fmt.Errorf("Not possible to os.Open file: %s\n", err)
}
defer osfile.Close()
// The default rune is 0
if gct.Separator != 0 {
gct.file.Comma = gct.Separator
}
// The default rune is 0
if gct.Comment != 0 {
gct.file.Comment = gct.Comment
}
gct.file = csv.NewReader(osfile)
gct.data, err = gct.file.ReadAll()
if err != nil {
return fmt.Errorf("Not possible to csv.ReadAll file: %s\n", err)
}
gct.getHeaders()
// First data row is 1
gct.Row = 1
// Last row number
gct.lastRow = len(gct.data) - 1
return nil
}
// getHeaders will associate the Headers names with the correct column number
func (gct *GoCSVtable) getHeaders() {
header := gct.data[0]
columnsNumber := len(header)
// Initiate Headers
gct.Headers = make(map[string]int)
for field := 0; field < columnsNumber; field++ {
name := header[field]
gct.Headers[name] = field
}
}
// Next will jump to the next CSV row. If file is over, will return an io.EOF
func (gct *GoCSVtable) Next() error {
if gct.Row >= gct.lastRow {
return io.EOF
}
gct.Row++
return nil
}
// GetNumberOfRows will return the number of data rows, not considering the
// header
func (gct *GoCSVtable) GetNumberOfRows() int {
return gct.lastRow
}
// Read return a specific field from active row
func (gct *GoCSVtable) Read(field string) string {
col := gct.Headers[field]
return gct.data[gct.Row][col]
}
// Read and return the entire row
func (gct *GoCSVtable) ReadRow(row int) ([]string, error) {
if row > gct.lastRow {
return []string{}, fmt.Errorf("Not possible to read row %v. Data has max of %v rows.\n", row, gct.lastRow)
}
return gct.data[row], nil
}
// ReadCol will return a slice with all row values from a single column (field)
func (gct *GoCSVtable) ReadCol(field string) ([]string, error) {
data := []string{}
fieldNumber := gct.Headers[field]
for row := 1; row <= gct.lastRow; row++ {
data = append(data, gct.data[row][fieldNumber])
}
return data, nil
}

84
gocsvtable_test.go Normal file
View File

@ -0,0 +1,84 @@
package gocsvtable
import (
"io"
"testing"
)
const testFile = "test.csv"
func TestOpenCSV(t *testing.T) {
gct := GoCSVtable{}
err := gct.OpenCSV(testFile)
if err != nil {
t.Errorf("\nError opening csv file:\n - %#v\n", err.Error())
}
}
func TestGetHeaders(t *testing.T) {
const letters = 0
const numbers = 1
gct := GoCSVtable{}
gct.OpenCSV(testFile)
gotLettersCol := gct.Headers["Letters"]
if gotLettersCol != letters {
t.Errorf("Error reading correct 'Letters' column. Expected: '%v'. Got: '%v'.\n", letters, gotLettersCol)
}
gotNumbersCol := gct.Headers["Numbers"]
if gotNumbersCol != numbers {
t.Errorf("Error reading correct 'Numbers' column. Expected: '%v'. Got: '%v'.\n", numbers, gotNumbersCol)
}
}
func TestNext(t *testing.T) {
gct := GoCSVtable{}
gct.OpenCSV(testFile)
for row := 2; row < 5; row++ {
err := gct.Next()
if err != nil {
t.Errorf("Error passing to next row. CSV file have 5 rows, not %v", row)
}
}
// Try to go to different row, it should receive io.EOF
err := gct.Next()
if err != io.EOF {
t.Errorf("Error on Next(), row should be inexistent. Expected: '%v'; Got: %v", io.EOF, err)
}
}
// // GetNumberOfRows will return the number of data rows, not considering the
// // header
// func (gct *GoCSVtable) GetNumberOfRows() int {
// return gct.lastRow
// }
// // Read return a specific field from active row
// func (gct *GoCSVtable) Read(field string) string {
// col := gct.Headers[field]
// return gct.data[gct.Row][col]
// }
// // Read and return the entire row
// func (gct *GoCSVtable) ReadRow(row int) ([]string, error) {
// if row > gct.lastRow {
// return []string{}, fmt.Errorf("Not possible to read row %v. Data has max of %v rows.\n", row, gct.lastRow)
// }
// return gct.data[row], nil
// }
// // ReadCol will return a slice with all row values from a single column (field)
// func (gct *GoCSVtable) ReadCol(field string) ([]string, error) {
// data := []string{}
// fieldNumber := gct.Headers[field]
// for row := 1; row <= gct.lastRow; row++ {
// data = append(data, gct.data[row][fieldNumber])
// }
// return data, nil
// }

82
tags Normal file
View File

@ -0,0 +1,82 @@
!_TAG_EXTRA_DESCRIPTION anonymous /Include tags for non-named objects like lambda/
!_TAG_EXTRA_DESCRIPTION fileScope /Include tags of file scope/
!_TAG_EXTRA_DESCRIPTION pseudo /Include pseudo tags/
!_TAG_EXTRA_DESCRIPTION subparser /Include tags generated by subparsers/
!_TAG_FIELD_DESCRIPTION epoch /the last modified time of the input file (only for F\/file kind tag)/
!_TAG_FIELD_DESCRIPTION file /File-restricted scoping/
!_TAG_FIELD_DESCRIPTION input /input file/
!_TAG_FIELD_DESCRIPTION name /tag name/
!_TAG_FIELD_DESCRIPTION pattern /pattern/
!_TAG_FIELD_DESCRIPTION typeref /Type and name of a variable or typedef/
!_TAG_FIELD_DESCRIPTION!Go package /the real package specified by the package name/
!_TAG_FIELD_DESCRIPTION!Go packageName /the name for referring the package/
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_KIND_DESCRIPTION!DTD E,entity /entities/
!_TAG_KIND_DESCRIPTION!DTD a,attribute /attributes/
!_TAG_KIND_DESCRIPTION!DTD e,element /elements/
!_TAG_KIND_DESCRIPTION!DTD n,notation /notations/
!_TAG_KIND_DESCRIPTION!DTD p,parameterEntity /parameter entities/
!_TAG_KIND_DESCRIPTION!Go M,anonMember /struct anonymous members/
!_TAG_KIND_DESCRIPTION!Go P,packageName /name for specifying imported package/
!_TAG_KIND_DESCRIPTION!Go Y,unknown /unknown/
!_TAG_KIND_DESCRIPTION!Go a,talias /type aliases/
!_TAG_KIND_DESCRIPTION!Go c,const /constants/
!_TAG_KIND_DESCRIPTION!Go f,func /functions/
!_TAG_KIND_DESCRIPTION!Go i,interface /interfaces/
!_TAG_KIND_DESCRIPTION!Go m,member /struct members/
!_TAG_KIND_DESCRIPTION!Go n,methodSpec /interface method specification/
!_TAG_KIND_DESCRIPTION!Go p,package /packages/
!_TAG_KIND_DESCRIPTION!Go s,struct /structs/
!_TAG_KIND_DESCRIPTION!Go t,type /types/
!_TAG_KIND_DESCRIPTION!Go v,var /variables/
!_TAG_KIND_DESCRIPTION!Markdown S,subsection /level 2 sections/
!_TAG_KIND_DESCRIPTION!Markdown T,l4subsection /level 4 sections/
!_TAG_KIND_DESCRIPTION!Markdown c,chapter /chapters/
!_TAG_KIND_DESCRIPTION!Markdown h,hashtag /hashtags/
!_TAG_KIND_DESCRIPTION!Markdown n,footnote /footnotes/
!_TAG_KIND_DESCRIPTION!Markdown s,section /sections/
!_TAG_KIND_DESCRIPTION!Markdown t,subsubsection /level 3 sections/
!_TAG_KIND_DESCRIPTION!Markdown u,l5subsection /level 5 sections/
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_OUTPUT_VERSION 0.0 /current.age/
!_TAG_PARSER_VERSION!DTD 0.0 /current.age/
!_TAG_PARSER_VERSION!Go 0.0 /current.age/
!_TAG_PARSER_VERSION!Markdown 1.1 /current.age/
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
!_TAG_PROC_CWD /run/media/bruno/Multimedia/MyDocuments/Development/BrunoFontes/GO/go-csv-table/ //
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 6.1.0 /v6.1.0/
!_TAG_ROLE_DESCRIPTION!DTD!element attOwner /attributes owner/
!_TAG_ROLE_DESCRIPTION!DTD!parameterEntity condition /conditions/
!_TAG_ROLE_DESCRIPTION!DTD!parameterEntity elementName /element names/
!_TAG_ROLE_DESCRIPTION!DTD!parameterEntity partOfAttDef /part of attribute definition/
!_TAG_ROLE_DESCRIPTION!Go!package imported /imported package/
!_TAG_ROLE_DESCRIPTION!Go!unknown receiverType /receiver type/
Comment gocsvtable.go /^ Comment rune$/;" m struct:gocsvtable.GoCSVtable typeref:typename:rune
GetNumberOfRows gocsvtable.go /^func (gct *GoCSVtable) GetNumberOfRows() int {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:int
GoCSVtable gocsvtable.go /^type GoCSVtable struct {$/;" s package:gocsvtable
Headers gocsvtable.go /^ Headers map[string]int$/;" m struct:gocsvtable.GoCSVtable typeref:typename:map[string]int
Next gocsvtable.go /^func (gct *GoCSVtable) Next() error {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:error
OpenCSV gocsvtable.go /^func (gct *GoCSVtable) OpenCSV(filename string) error {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:error
Read gocsvtable.go /^func (gct *GoCSVtable) Read(field string) string {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:string
ReadCol gocsvtable.go /^func (gct *GoCSVtable) ReadCol(field string) ([]string, error) {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:([]string, error)
ReadRow gocsvtable.go /^func (gct *GoCSVtable) ReadRow(row int) ([]string, error) {$/;" f struct:gocsvtable.GoCSVtable typeref:typename:([]string, error)
Row gocsvtable.go /^ Row int$/;" m struct:gocsvtable.GoCSVtable typeref:typename:int
Separator gocsvtable.go /^ Separator rune$/;" m struct:gocsvtable.GoCSVtable typeref:typename:rune
TestGetHeaders gocsvtable_test.go /^func TestGetHeaders(t *testing.T) {$/;" f package:gocsvtable
TestNext gocsvtable_test.go /^func TestNext(t *testing.T) {$/;" f package:gocsvtable
TestOpenCSV gocsvtable_test.go /^func TestOpenCSV(t *testing.T) {$/;" f package:gocsvtable
data gocsvtable.go /^ data [][]string$/;" m struct:gocsvtable.GoCSVtable typeref:typename:[][]string
file gocsvtable.go /^ file *csv.Reader$/;" m struct:gocsvtable.GoCSVtable typeref:typename:*csv.Reader
getHeaders gocsvtable.go /^func (gct *GoCSVtable) getHeaders() {$/;" f struct:gocsvtable.GoCSVtable
go-csv-table README.md /^# go-csv-table$/;" c
gocsvtable gocsvtable.go /^package gocsvtable$/;" p
gocsvtable gocsvtable_test.go /^package gocsvtable$/;" p
lastRow gocsvtable.go /^ lastRow int$/;" m struct:gocsvtable.GoCSVtable typeref:typename:int
rows gocsvtable.go /^ rows int$/;" m struct:gocsvtable.GoCSVtable typeref:typename:int
testFile gocsvtable_test.go /^const testFile = "test.csv"$/;" c package:gocsvtable

5
test.csv Normal file
View File

@ -0,0 +1,5 @@
Letters,Numbers
a,1
b,2
c,3
d,4
1 Letters Numbers
2 a 1
3 b 2
4 c 3
5 d 4