Como juntar múltiplas linhas com base em um padrão?

Como juntar múltiplas linhas com base em um padrão?

Quero juntar várias linhas em um arquivo com base em um padrão compartilhado por ambas as linhas.

Este é o meu exemplo:

{101}{}{Apples}
{102}{}{Eggs}
{103}{}{Beans}
{104}...
...

{1101}{}{This is a fruit.}
{1102}{}{These things are oval.}
{1103}{}{You have to roast them.}
{1104}...
...

Eu quero entrar nas linhas {101}{}{Apples}e{1101}{}{This is a fruit.}

para uma linha {101}{}{Apples}{1101}{}{This is a fruit.}para processamento posterior.

O mesmo vale para as outras linhas.

Como você pode ver, ambas as linhas compartilham o número 101, mas não tenho ideia de como fazer isso. Alguma ideia?

/EDITAR:

Encontrei uma "solução alternativa":

Primeiro, exclua todos os caracteres "{1" anteriores do grupo dois no modo VISUAL BLOCK com C-V(ou atalho semelhante), depois classifique todas as linhas por número com :%sort ne junte cada segunda linha com :let @q = "Jj"seguido de 500@q.

Isso funciona, mas me deixa com {101}{}{Apples} 101}{}{This is a fruit.}. Eu precisaria então adicionar os caracteres ausentes "{1" em cada linha, não exatamente o que desejo. Qualquer ajuda será apreciada.

Responder1

Em vez de excluir o {1, basta fazer

:%sort rn /\d\d\d}/

Isso fará uma classificação numérica, mas em cada linha serão visualizados apenas três dígitos seguidos por um }.

Além disso, para juntar as linhas depois, eu faria

:g/{\d\d\d}/j!

Responder2

Aqui está uma maneira de fazer isso no shell com um arquivo:

join -j 2 \
    <(sed -n '/^{...}/{s/{/{ /;s/}/ }/;p}' inputfile) \
    <(sed -n '/^{....}/{s/{./& /;s/}/ }/;p}' inputfile) |
    sed 's/^\([^ ]*\) { }{}\({[^}]*}\) {1 }\({.*}\)$/{\1}{}\2{1\1}\3/'

Ele usa as duas primeiras invocações de sedpara dividir o arquivo com base no número de dígitos entre o primeiro conjunto de chaves e adiciona espaços ao redor dos últimos três dígitos ( {101}torna-se { 101 }e {1101}torna-se {1 101 }). Em seguida, ele usa esses números de três dígitos como campo para a jointecla de comando ativada. O último sedcomando coloca os dígitos de volta onde eles pertencem e remove os espaços extras adicionados anteriormente.

Um vimguru provavelmente poderia fazer algo melhor internamente vim. Eu poderia fazer algo mais simples do que o acima usando o AWK.

Responder3

Aqui está um exemplo de uso do editor Vim/Ex na linha de comando para um padrão:

$ ex +'redir @a|sil g/101}/' +'redi>>/dev/stdout|echon join(split(@a),"")' -scq! input.txt 
{101}{}{Apples}{1101}{}{This is a fruit.}

Para vários padrões, repita com comandos extras, adicione um loop ou faça um loop a partir do shell, por exemplo

$ for i in `seq 1 3`; do ex +"redir @a|sil g/10$i}/" +'redi>>/dev/stdout|echo join(split(@a),"")' -scq! input.txt; done
{101}{}{Apples}{1101}{}{Thisisafruit.}
{102}{}{Eggs}{1102}{}{Thesethingsareoval.}
{103}{}{Beans}{1103}{}{Youhavetoroastthem.}

Usando apenas shell para analisar os dados, é muito mais simples, por exemplo:

$ grep "101}" input.txt | xargs
{101}{}{Apples} {1101}{}{This is a fruit.}

Para múltiplas linhas:

$ for i in `seq 1 4`; do grep "10$i}" input.txt | xargs; done
{101}{}{Apples} {1101}{}{This is a fruit.}
{102}{}{Eggs} {1102}{}{These things are oval.}
{103}{}{Beans} {1103}{}{You have to roast them.}

informação relacionada