J'ai un fichier CSV que je passe par un ensemble de commandes awk / sed.

Certaines lignes du fichier CSV ressemblent à ceci:

10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,"[1.1 - 3.0]","[0.384 - 0.768]"      

Où les 8e et 9e colonnes sont une chaîne représentant une plage numérique.

Comment puis-je utiliser awk ou sed pour remplacer ces champs par une valeur numérique? Soit le début de la plage, soit la fin de la plage?

Donc cette ligne finirait comme

10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,1.1,0.384      

Ou

10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,3.0,0.768

Je suis arrivé jusqu'à en supprimant les crochets mais au-delà je suis bloqué J'ai envisagé de diviser sur le "-", mais de nombreuses lignes de mon fichier ont une valeur numérique régulière, pas une plage, dans ces deux dernières colonnes, et cela complique les choses (je ne veux pas finir avec certaines lignes ayant un nombre différent de colonnes).

2
ff524 17 janv. 2017 à 04:30

2 réponses

Meilleure réponse

Voici une commande sed qui prendra chaque plage et la divisera en deux champs. Il recherche des chaînes comme "[A - B]" et les convertit en A,B. Il peut facilement être modifié pour n'utiliser qu'une des valeurs si nécessaire en modifiant la partie \1,\2. L'expression régulière suppose que tous les nombres ont au moins un chiffre de chaque côté d'une décimale requise. Ainsi, 1, .5 et 3. ne seraient pas valides. Si vous en avez besoin, le regex peut être rendu plus accommodant.

$ cat file
10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,"[1.1 - 3.0]","[0.384 - 0.768]"
$ sed -Ee 's|"\[([0-9]+\.[0-9]+) - ([0-9]+\.[0-9]+)\]"|\1,\2|g' file
10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,1.1,3.0,0.384,0.768
2
Harvey 17 janv. 2017 à 02:26

Puisque vos données sont basées sur un champ , awk est le choix logique.

Notez que si awk ne connaît généralement pas les champs entre guillemets , ce n'est pas un problème ici, car les champs entre guillemets ne sont pas intégrés , instances.

#!/usr/bin/env bash

useStart1=1  # set to `0` to use the *end* of the *penultimate* fields' range instead.
useStart2=1  # set to `0` to use the *end* of the *last* field's range instead.
awk -v useStart1=$useStart1 -v useStart2=$useStart2 '
  BEGIN { FS=OFS="," }
  { 
        split($(NF-1), tokens1, /[][" -]+/)
        split($NF,     tokens2, /[][" -]+/)
        $(NF-1) = useStart1 ? tokens1[2] : tokens1[3]
        $NF =     useStart2 ? tokens2[2] : tokens2[3]
        print
  }
' <<'EOF'
10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,"[1.1 - 3.0]","[0.384 - 0.768]"
EOF

Le code ci-dessus donne:

10368,"Verizon DSL",DSL,NY,NORTHEAST,-5,-4,1.1,0.384

La modification des valeurs de $useStart1 et $useStart2 produit les variations appropriées.

1
mklement0 20 janv. 2017 à 00:05