Éléments csv entre guillemets doubles dans Golang

Chose que tu veux faire

Depuis Format général du fichier CSV (traduction japonaise RFC4180)

Chaque champ (dans l'enregistrement) peut ou non être entre guillemets

Il y a une déclaration, donc selon le projet, mettons-la entre guillemets! Je pense que cela peut devenir. C'était la même chose pour moi.

Donc, comme le titre l'indique, ** Golang va double-citer chaque élément de csv! ** C'est ce que je veux faire cette fois.

Cependant, avec l'encodeur csv standard de golang, "" est toujours ajouté comme caractère d'échappement, donc il devient "" colonne "" "" colonne "" "`. Qu'est-ce qui ne va pas

Conclusion

En gros, utilisez gocsv. Traitement d'encodage comme celui-ci, la sortie est comme ça.

client_id,client_name,client_age
12,John,21
13,Fred,
14,James,32
15,Danny,

<détails>

Code complet </ summary>

base.go


package main

import (
	"fmt"
	"bytes"

	"github.com/gocarina/gocsv"
)

type Client struct { // Our example struct, you can use "-" to ignore a field
	Id      string `csv:"client_id"`
	Name    string `csv:"client_name"`
	Age     string `csv:"client_age"`
	NotUsed string `csv:"-"`
}

//base data
func basedata() []*Client {
	clients := []*Client{}
	clients = append(clients, &Client{Id: "12", Name: "John", Age: "21"}) // Add clients
	clients = append(clients, &Client{Id: "13", Name: "Fred"})
	clients = append(clients, &Client{Id: "14", Name: "James", Age: "32"})
	clients = append(clients, &Client{Id: "15", Name: "Danny"})
	return clients
}

func main() {
	clients := basedata()
	out := bytes.Buffer{}
	err := gocsv.Marshal(&clients, &out) // Get all clients as CSV string
	if err != nil {
		panic(err)
	}
	csvContent := out.Bytes()
	fmt.Println(string(csvContent)) // Display all clients as CSV string

}

Peu importe la quantité de "" ʻest attachée à chaque élément avant l'encodage, elle peut être changée en "" " par Marshal, donc changez votre façon de penser. Une fois que vous avez décodé la chaîne d'octets encodée, vous pouvez l'obtenir sous forme de chaîne pour chaque élément, alors attachez-y "" `.

Puisque gocsv peut contrôler les délimiteurs et les codes de saut de ligne, il est pris à partir de là.

Par défaut, c'est la valeur de gocsv.SafeCSVWriter qui peut être obtenue en exécutant gocsv.DefaultCSVWriter, donc, . Le code de saut de ligne est «\ n».

Ces informations peuvent changer avec gocsv.SetCSVWriter, veuillez donc les modifier en fonction de votre implémentation.

L'exemple est ici, et le traitement est extrait. Gist

base.go


//Passez le deuxième argument du maréchal tel quel
func convert(b *bytes.Buffer) ([]byte, error) {
        //retry to decode, to check ""
        reader := csv.NewReader(b)
        reader.LazyQuotes = true
        lines, err := reader.ReadAll()
        if err != nil {
                return []byte{}, err
        }

        //rewrite to add "", escape \"
        bytes := make([]byte, 0, len(b.Bytes())*2)

        //If you update writer by SetCSVWriter, please change the delimiter which you use
        delimiter := ','
        //If you update writer by SetCSVWriter, please change the crlf which you use
        for _, line := range lines {
                for i, part := range line {
                        if i != 0 {
                                bytes = append(bytes, byte(delimiter))
                        }
                        bytes = append(bytes, []byte(escape(part))...)
                }
                bytes = append(bytes, byte('\r'))
        }
        return bytes, nil
}

func escape(part string) string {
        //"XXX" => XXX
        escapeStr := strings.Replace(part, "\"", "\"\"", -1)
        return "\"" + escapeStr + "\""
}

Résultat de l'exécution. Si vous souhaitez conserver la balise telle quelle, vous pouvez ajuster la boucle des lignes dans convert et sauter le début.

"client_id","client_name","client_age"
"12","John","21"
"13","Fred",""
"14","James","32"
"15","Danny",""

<détails>

Bonus </ summary>

Bonus Contexte de la conclusion

Profitez du samedi soir de l'oncle qui a du mal à implémenter CSV à Golang

Déclencheur: Il y avait une histoire disant "Je ne peux pas gérer les doubles citations de csv!", Alors je l'ai étudiée.

En utilisant l'article de référence comme indice, je me demande si ce serait une bonne idée de l'envelopper quelque part dans l'encodeur. Ci-dessous le flux de l'enquête de boue

  • Puis-je utiliser SetCSVWriter dans gocsv pour écraser csv.Writer dans io.Writer et ʻencoding / csv`?
  • Puisque io.Writer contrôle la chaîne d'octets, la création de la vôtre ici n'est pas différente de la création de votre propre analyseur csv. Rejeté
  • Puisque le côté encodage / csv échange la structure définie en interne au lieu de l'interface, il est impossible d'écraser en raison des spécifications de golang.
  • → Cette idée est inutile! ――Au contraire, pouvez-vous changer l'écrivain utilisé par gocsv et exécuter divers processus pour ajouter " ? --Gocsv définit une interface appelée CSVWriter! On dirait qu'il peut être utilisé!
  • Non, il est possible d'enregistrer la fonction de génération d'écrivain avec SetCSVWriter, mais l'argument de la fonction est «* SafeCSVWriter» au lieu de «CSVWriter». Le moule ne rentre pas. .. .. ――Mais en ce qui concerne l'utilisation de gocsv, je n'utilise pas SafeCSVWriter autre que l'interface de CSVWriter! Cela fonctionne-t-il même si la définition est changée en CSVWriter?
  • fork et essayez d'écraser CSVWriter. Oh, je peux y aller! ――Veuillez emballer l'exemple de code de double devis! Ce serait formidable si vous pouviez l'incorporer officiellement, eh bien. Voulez-vous écrire un test dans un cas réel en déplaçant votre propre CSVWriter? ――Wow, le jeu de guillemets doubles avec ceci a été échappé! ――Il semble bon jusqu'à présent, mais il semble que cela ne puisse pas être résolu
  • Le décodage de gocsv est bon pour gérer "Vous pouvez obtenir des données pour chaque élément!
  • Ensuite, si vous supprimez le code de guillemets doubles que vous avez fait ci-dessus en unités de colonne, vous pouvez obtenir les caractères sans échapper! Ne devrions-nous pas utiliser ceci pour écrire dans «[] byte» et le reconstruire? --Oui vous pouvez. Le "escape" dans la chaîne est également manquant, alors ajoutons-le! --D'ACCORD! Ça s'est bien passé! Après une pause, publiez un PR sur gocsv et c'est une solution! -... ça, n'est-ce pas inutile de jouer avec CSVWriter?

C'est Saturday Night Fever qui a débogué et corrigé le code officiel qui s'est soldé en vain.

Je me demandais si je publierais les traces de mes efforts, mais je pensais que cela n'en valait pas la peine car le nombre de cas d'utilisation est devenu nul, alors je l'ai mis en attente. J'ai fini par écrire cet article et Gist à la place

référence

Format général du fichier CSV (traduction japonaise RFC4180) 4.1.6 Règles de description du format CSV Lors de la sortie de CSV avec golang, les éléments ne peuvent pas être placés entre guillemets gocsv officiel

Recommended Posts