Duplicar linhas e torná-las únicas?

2

Eu tenho a seguinte estrutura de linhas de texto:

3923 001    L05 LV,L05 RM
3923 002    L12 RA,L12 LA
3923 003    I06 ALL
3923 004    G04 RV,Z09 ALL

mas eu precisaria disso:

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

Isso é possível com um regex?

Basicamente, eu preciso de cada linha copyd a quantidade de vezes que contém um "," e, em seguida, feita única a partir do 10º caractere; se eu pudesse fazer a primeira parte, então apenas uma cópia de cada linha x a quantidade de vírgula, eu poderia limpar o resto manualmente

    
por Randy V 16.07.2015 / 10:41

5 respostas

7

Dado o formato do seu exemplo, isso deve funcionar para qualquer número de strings separadas por vírgula após o espaço inicial grande (se for uma guia, basta alterar os espaços no segundo s/// to \t

sed ':;h;s/,.*//;p;x;s/    [^,]*,/    /;t;d' file

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

Se você quiser guias,

if you want to write the tab as \t, you can give it to Bash using $'' quotes: sed $':;h;s/,.*//;p;x;s/\t[^,]*,/ /;t;d'. Or just insert a literal tab (for bash, you need to type control-v to enter it literally). .

Toby Speight
    
por 16.07.2015 / 11:05
3

É possível usar sed. Pipe a entrada para o abaixo.

| sed 's/\(^.\{12\}\)\([^,]\+\),\([^,]\+\)/\n/'

saída

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL
3923 004    G04 RV
3923 004    Z09 ALL

Aqui está a fonte para manipular a entrada com vários ","

Para entrada original sem aba, use

| perl -ne '/,/ && do {chomp;s/^(.{12})(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'

Se a entrada tiver uma guia, use

| perl -ne '/,/ && do{chomp; s/^([^\t]+\t)(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'
    
por 16.07.2015 / 10:52
2

Possível solução com awk :

awk -F" " '{ x = $3 " " $4 " " $5; split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file

O resultado deve ser:

3923 001    L05 LV
3923 001    L05 RM
3923 002    L12 RA
3923 002    L12 LA
3923 003    I06 ALL 
3923 004    G04 RV
3923 004    Z09 ALL

E se sua entrada contiver vários , como nos comentários: 3923 001 L05 LV,L05 RM,L09 AB , você pode tentar:

awk -F" " '{ x = $3; for (i = 4; i <= NF; i++) { x = x " " $i; } split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file
    
por 16.07.2015 / 10:54
1

Variante simplificada de Resposta do usuário112638726

sed ':1;s/\(\(.*\s\s\+\)[^,]\+\),/\n/;t1'
sed -r ':1;s/((.+\s\s+)[^,]+),/\n/;t1'

escolherá a parte repetida como «qualquer símbolo antes de 2 (ou mais) espaços».

Então você pode canalizar a saída por meio de

uniq -s 10
    
por 16.07.2015 / 11:52
1

Você pode usar awk e definir o separador de campos para espaços ou vírgulas. Em seguida, faça um loop em blocos de 2, imprimindo o primeiro e o segundo campos junto com blocos de dois:

$ awk -v FS='(\s+|,)' '{for (i=3; i<=NF; i+=2) print $1, $2, $i, $(i+1)}' file
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL
    
por 16.07.2015 / 13:30