0
votes

Convertir TSV en CSV, où le champ TSV contient des virgules

J'ai un TSV avec des champs qui ressemblent à:

name, location,1 2 3 4 5,

Quand j'utilise sed 's / \ w /, / g' Je me retrouve avec un csv où 1, 2, 3, 4 et 5 sont considérés comme des entrées séparées. Je voudrais que ce soit '1 2 3 4 5' J'ai essayé de convertir des virgules en espace blanc avant d'exécuter la commande ci-dessus en utilisant

sed 's/,/\w/g' 

mais lors de la conversion de l'espace blanc en virgules, il inclut des espaces blancs simples ainsi que les tabulations, donc qu'est-ce que l'expression régulière pour un seul caractère d'espacement?

Sortie souhaitée:

name   location   1,2,3,4,5

sed

4 commentaires

Êtes-vous sûr que le fichier d'entrée est séparé par des tabulations ou s'agit-il simplement d'un groupe d'espaces?


Dans mon éditeur de texte (texte sublime), ils ressemblent à des onglets


les séparateurs dans les valeurs CSV sont généralement gérés en plaçant les valeurs entre guillemets, par exemple nom, emplacement, "1,2,3,4,5" . Estimeriez-vous une telle solution acceptable?


Ouais ce serait super


4 Réponses :


2
votes

Comme mentionné dans un commentaire, CSV traite généralement les occurrences de son caractère séparateur dans les valeurs en mettant la valeur entre guillemets, donc je vous suggère simplement de traiter cela en mettant chaque valeur entre guillemets:

sed -E 's/"/\\"/g;s/\t+$//;s/^/"/;s/\t/","/g;s/$/"/'

Vous pouvez l'essayer ici .

Cela laisse une virgule comme dans votre exemple sortie, si vous voulez l'éviter, vous pouvez utiliser ce qui suit:

s/\t+$//

Si vos données d'origine contiennent ", vous devrez cependant les échapper, que vous pouvez réaliser en ajoutant la substitution suivante avant les autres:

s/"/\\"/g

Comme Ed Morton suggère que nous puissions également supprimer les champs vides de fin:

sed -E 's/\t+$//;s/^/"/;s/\t/","/g;s/$/"/'

En conclusion, j'utiliserais ce qui suit:

sed -E 's/([^\t]*)(\t|$)/"\1",/g'


3 commentaires

@EdMorton, la virgule de fin était dans l'exemple de sortie d'OP et ma réponse le mentionne et propose une alternative. J'ai cependant résolu les deux autres problèmes.


Wow, je n'ai même pas remarqué que l'OP voulait changer toutes ses virgules en blancs dans ce dernier champ non plus! Ce que vous avez maintenant est meilleur, mais cela supprimerait tout champ vide à la fin d'une ligne.


Je viens de voter et j'ai remarqué que le CSV résultant cassait jquery-csv. Après de nombreuses recherches, j'ai découvert que vous deviez échapper aux guillemets doubles avec un autre guillemet double ! La commande résultante serait donc sed -E 's / "/" "/ g; s / \ t + $ //; s / ^ /" /; s / \ t / "," / g; s / $ / "/ ', qui a bien fonctionné pour mes besoins.



1
votes

Remplacez les tabulations par "," et placez les lignes entre guillemets ou remplacez les virgules par des espaces et les tabulations par des virgules. Dans les deux cas, vous obtiendrez un fichier CSV valide.

$ cat file
name    location        1,2,3,4,5
$
$ sed 's/\t/","/g; s/^\|$/"/g' file
"name","location","1,2,3,4,5"
$
$ sed 's/,/ /g; s/\t/,/g' file
name,location,1 2 3 4 5


0 commentaires

1
votes

Et dans awk:

$ awk -v OFS="," '{          # output delimiter to a comma *
    for(i=1;i<=NF;i++)       # loop all fields
        if($i~/,/)           # if comma in field
            $i="\"" $i "\""  # surround with quotes **
    $1=$1                    # rebuild record
}1' file                     # output

Expliqué:

$ awk -v OFS="," '{for(i=1;i<=NF;i++)if($i~/,/)$i="\"" $i "\"";$1=$1}1' file
name,location,"1,2,3,4,5"

* s'il y a de l'espace dans l'enregistrement, considérez le séparateur de champ de saisie en un tab avec awk -F "\ t" .

** également, s'il y a des guillemets dans les champs avec des virgules, ils devraient peut-être être dupliqués ou échappés.


0 commentaires

0
votes

En fonction de vos besoins réels:

$ awk -F'\t' -v OFS=',' '{for (i=1;i<=NF;i++) $i="\""$i"\""} 1' file
"name","location","1,2,3,4,5"

$ awk -F'\t' -v OFS=',' '{for (i=1;i<=NF;i++) gsub(OFS," ",$i); $1=$1} 1' file
name,location,1 2 3 4 5

$ awk -F'\t' -v OFS=',' '{for (i=1;i<=NF;i++) gsub(OFS," ",$i); $(NF+1)=""} 1' file
name,location,1 2 3 4 5,

$ echo 'a"b' | awk -F'\t' -v OFS=',' '{for (i=1;i<=NF;i++) { gsub(/"/,"\"\"",$i); $i="\""$i"\"" } } 1'
"a""b"


0 commentaires