reemplazar - Cómo encontrar e imprimir un personaje específico en bash
recorrer string bash (4)
Perl al rescate!
No ha especificado cómo obtener la información del encabezado, por lo que en el siguiente guión, la matriz de encabezado @ se completa directamente.
%to_idx
hash mapea los nombres de las columnas en sus índices (A => 0, B => 1, etc.).
Cada línea se divide en campos, cada campo se compara con el esperado ( $next
) y se imprimen guiones si es necesario. Lo mismo ocurre con los campos finales perdidos.
#!/usr/bin/perl
use warnings;
use strict;
my @header = qw( A B C D E F );
my %to_idx = map +($header[$_] => $_), 0 .. $#header;
open my $IN, ''<'', shift or die $!;
while (<$IN>) {
chomp;
my @fields = split /,/;
print shift @fields;
my $next = 0;
for my $field (@fields) {
my ($name, $value) = split /=/, $field;
print '',-'' x ($to_idx{$name} - $next);
print ",$name=$value";
$next = $to_idx{$name} + 1;
}
print '',-'' x (1 + $#header - $next); # Missing trailing fields.
print "/n"
}
Tengo un archivo como:
AA,A=14,B=356,C=845,D=4516
BB,A=65,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,F=225
Nunca sé si en la fila falta el valor A, B, C o D. Pero necesito transformar este archivo como:
AA,A=14,B=356,C=845,D=4516,-,-
BB,A=65,-,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,-,-,F=225
Entonces, si falta algún valor, imprima solo -
marque. Mi plan tiene la misma cantidad de columnas para un análisis sencillo. Yo prefiero la solución awk. Gracias por cualquier consejo o ayuda.
Mi primer intento fue:
awk ''{gsub(/[,]/, "/t")}; BEGIN{ FS = OFS = "/t" } { for(i=1; i<=NF; i++) if($i ~ /^ *$/) $i = "-" }; {print $0}''
Pero luego noto que faltan algunos valores.
EDITAR:
Desde mi encabezado, sé que hay un valor A, B, C, D, E, F ...
Solución en TXR
@(do (defstruct fill-missing nil strings (hash (hash :equal-based)) (:postinit (self) (each ((s self.strings)) (set [self.hash s] "-"))) (:method add (self str val) (set [self.hash str] `@str=@val`)) (:method print (self stream) (put-string `@{(mapcar self.hash self.strings) ","}` stream)))) @(repeat) @ (bind fm @(new fill-missing strings ''#"A B C D E F")) @{label},@(coll)@{sym /[^,=]+/}=@{val /[^,]+/}@(do fm.(add sym val))@(end) @ (do (put-line `@label,@fm`)) @(end)
Correr:
$ txr missing.txr data AA,A=14,B=356,C=845,D=4516,-,- BB,A=65,-,C=255,D=841,E=5133,F=1428 CC,A=88,B=54,C=549,-,-,F=225
$ cat file.txt
AA,A=14,B=356,C=845,D=4516
BB,A=65,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,F=225
$ perl -F, -le ''@k=(A..F);
$op[0]=$F[0]; @op[1..6]=("-")x6;
$j=0; for($i=1;$i<=$#F;){ if($F[$i] =~ m/$k[$j++]=/){$op[$j]=$F[$i]; $i++} }
print join(",",@op)
'' file.txt
AA,A=14,B=356,C=845,D=4516,-,-
BB,A=65,-,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,-,-,F=225
-
-F,
divide la línea de entrada y guarda en@F
array -
-l
elimina la nueva línea de la línea de entrada, agrega nueva línea a la salida -
@k=(A..F);
inicializar array@k
conA
,B
, etc. hastaF
-
$op[0]=$F[0]; @op[1..6]=("-")x6;
initalize@op
array con el primer elemento de@F
y los seis elementos restantes como-
- for-loop itera sobre
@F
array, si el elemento coincide con el elemento@k
array en el índice correspondiente seguido de=
, cambia el elemento@op
-
print join(",",@op)
imprime la matriz@op
con,
como separador
BEGIN {
PROCINFO["sorted_in"]="@ind_str_asc" # order for for(i in a)
for(i=65;i<=90;i++) # create the whole alphabet to array a[]
a[sprintf("%c", i)] # you could read the header and use that as well
}
{
split($0,b,",") # split record by ","
printf "%s", b[1] # printf first element (AA, BB...)
delete b[1] # get rid of it
for(i in b)
b[substr(b[i],1,1)]=b[i] # take the first letter to use as index (A=12)
for(i in a) # go thru alphabet and printf from b[]
printf "%s%s", OFS, (i in b?b[i]:"-"); print ""
}
awk -v OFS=/, -f parsing.awk tbparsed.txt
AA,A=14,B=356,C=845,D=4516,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
BB,A=65,-,C=255,D=841,E=5133,F=1428,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
CC,A=88,B=54,C=549,-,-,F=225,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
Imprime "-" para cada letra que no se encuentra en el registro. Si los datos tuvieran un encabezado, podría split
en el arreglo 2-D b[NR]
y cambiar el de for(i in a)
por for(i in b[1]) ... printf ... b[NR][b[1][i]] ...
y si no necesita la primera columna estática, elimine la primera printf
y delete
.