Existe uma maneira de adicionar novas linhas a uma tabela para criar subgrupos?

4

Estou tendo muita dificuldade em descobrir como expressar isso de modo que o Google-fu falhe.

Eu tenho um arquivo de texto com uma tabela de dados. Gostaria de inserir novas linhas para separar subgrupos visualmente.

Por exemplo, se eu começar com:

jan   ford
jan   trillian
mar   trillian
sep   marvin

E o primeiro campo é o meu campo de subgrupo, então a saída deve ser:

jan   ford
jan   trillian

mar   trillian

sep   marvin

Eu posso fazer algo como ^(a-z){3}\t(.*)\n\t(.*)$ para identificar duas linhas em que o mês é o mesmo, mas não sei como corresponder quando elas são diferentes.

Idealmente, eu adoraria que isso fosse um regex que eu possa usar no BBedit, mas estou aberto a outras soluções.

    
por Dave Noonan 29.10.2015 / 13:18

3 respostas

5

Parece que bbedit é algum tipo de editor OSX pago. Eu tenho medo que nunca usei e não consigo instalar, então não posso ajudá-lo. Com base na regex que você mostra, ela tem sua própria sintaxe de expressão regular, portanto, é improvável que você encontre uma solução em um site geral * nix usando-a. No entanto, aqui estão algumas outras opções. Em ambos, a ideia é salvar o primeiro campo e imprimir uma linha em branco se for diferente da linha anterior:

$ awk '{if($1!=last && NR>1){print ""}last=$1;}1;' file
jan ford
jan trillian

mar trillian

sep marvin

awk é uma linguagem de script projetada para lidar com dados baseados em campo. Ele dividirá automaticamente cada linha em campos que podem ser chamados de $1 , $2 ... $N . Portanto, o script acima salvará o primeiro campo na variável last e, para cada linha, exceto a primeira (isso é o que o NR>1 significa), ela imprimirá uma linha vazia se last não for igual ao valor valor atualmente salvo. O 1; é um atalho do awk para "imprimir todas as linhas".

Como alternativa, você também pode fazer isso em perl :

$ perl -lape '$F[0] ne $last && $.>1 && print ""; $last=$F[0]' file
jan ford
jan trillian

mar trillian

sep marvin

Aqui, estamos usando as opções de linha de comando perl para fazer a maior parte do trabalho. O -a faz com que perl aja como awk e divida cada linha de entrada na matriz @F . Portanto, $F[0] é o primeiro campo. O -l faz com que perl adicione uma nova linha a cada print , então print "" apenas imprime uma linha vazia. O -p faz com que imprima cada linha de entrada depois de aplicar o script fornecido por -e . O script em si é exatamente igual ao awk acima.

    
por 29.10.2015 / 14:16
4
awk 'NR > 1 && $1 != last {print ""}; {print; last = $1}'
    
por 29.10.2015 / 14:05
2

Como você pode combinar os dups, então você vai querer negar sua ação. Você poderia fazer como:

sed -e'/^\n/!{$n;G;N;s/^\(\(...\).*\)\n//;}' -eP\;D <in >out

Em outras palavras, inicie com um arquivo de espaço duplo e retire o segundo espaço entre seus grupos.

Em relação a suas impressões de entrada de exemplo:

jan   ford
jan   trillian

mar   trillian

sep   marvin

O que realmente me leva a uma pergunta para você: Eu acho que tenho como Trillian pode ter dois aniversários com os universos paralelos e tudo mais, mas você poderia explicar por que você acha que Marvin pode ter um? Eu acho que setembro caberia, porém - é sempre sombrio.

Aqui está outra, cortesia @don_crissti (se for ligeiramente modificada) :

sed -etD -e'$q;N;/^\(...\).*\n/!s/\n/&&/;:D' -eP\;D

Eu gosto dele muito melhor. Ele inicialmente perguntou-me: por que editar as novas linhas e não apenas editá-las? Eu não tinha nenhuma resposta, na verdade, e era principalmente ambivalente porque eu não a considerava muito diferença.

A coisa é, no entanto, a técnica de lookahead usada aqui requer um buffer de ponta de faca - ela pode relatar falsos positivos se o buffer ficar maior do que as duas linhas de entrada mais atuais de cada vez. Equilibrar uma única linha de visão torna-se mais difícil quando você também está inserindo novas linhas no mesmo fluxo que você está combinando e exige que você possa distinguir facilmente entre uma linha de entrada inserida ou uma linha que precisa ler. Esse equilíbrio exige pelo menos um teste extra por ciclo - e eu fico com o teste /^\n/! acima.

Mas uma parte muito básica da maquinaria sed é o retorno s/// ested da instrução t ubstitution, que faz a ramificação condicional no caso de sucesso. Como suas substituições sempre geram uma linha extra, o ciclo de linha sed - que é o que limpa o retorno de t est - não passa quando o espaço de padrão é D eleted e t est ainda funciona na parte superior do roteiro. Dessa forma, don pode simplesmente t est sobre cada inserção e avaliar com segurança o resultado da iteração anterior no topo da próxima.

Então, vá para cima de uma de suas respostas, porque eu acho que ele não vai colocar aqui.

O comando G et anexa espaço de espera de sed ao espaço de padrão após um delimitador% e_line \n inserido. O espaço de espera nunca é usado aqui e, portanto, tudo o que é G ot é o \n ewline.

O comando N ext anexa a linha de entrada N ext ao espaço padrão seguindo um delimitador% e_line% coilite% inserido. Fazer \n et, em seguida, G ext para cada linha de entrada recebe dois N ewlines por linha de entrada.

    
por 29.10.2015 / 13:34