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 n
e 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 sed
para 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 join
tecla de comando ativada. O último sed
comando coloca os dígitos de volta onde eles pertencem e remove os espaços extras adicionados anteriormente.
Um vim
guru 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.}