¿Cómo unir varias líneas según un patrón?

¿Cómo unir varias líneas según un patrón?

Quiero unir varias líneas en un archivo según un patrón que comparten ambas líneas.

Este es mi ejemplo:

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

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

Quiero unirme a las líneas {101}{}{Apples}y{1101}{}{This is a fruit.}

a una línea {101}{}{Apples}{1101}{}{This is a fruit.}para su posterior procesamiento.

Lo mismo ocurre con las otras líneas.

Como puede ver, ambas líneas comparten el número 101, pero no tengo idea de cómo lograrlo. ¿Algunas ideas?

/EDITAR:

Encontré una "solución alternativa":

Primero, elimine todos los caracteres "{1" anteriores del grupo dos en el modo VISUAL BLOCK con C-V(o un atajo similar), luego ordene todas las líneas por número con :%sort ny luego una cada segunda línea con :let @q = "Jj"seguido de 500@q.

Esto funciona, pero me deja con {101}{}{Apples} 101}{}{This is a fruit.}. Luego necesitaría agregar los caracteres faltantes "{1" en cada línea, lo que no es exactamente lo que quiero. Cualquier ayuda se agradece.

Respuesta1

En lugar de eliminar el {1, simplemente hazlo.

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

Eso hará una clasificación numérica, pero en cada línea solo verá tres dígitos seguidos de }.

Además, para unir las líneas después, haría

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

Respuesta2

Aquí hay una manera de hacerlo en el shell con un archivo:

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

Utiliza las dos primeras invocaciones de sedpara dividir el archivo según el número de dígitos entre el primer conjunto de llaves y agrega espacios alrededor de los últimos tres dígitos ( {101}se convierte { 101 }y {1101}se convierte {1 101 }). Luego usa esos números de tres dígitos como campo para joinactivar la tecla de comando. El último sedcomando devuelve los dígitos a su lugar y elimina los espacios adicionales agregados anteriormente.

Un vimgurú probablemente podría hacer algo mejor en su interior vim. Podría hacer algo más sencillo que lo anterior usando AWK.

Respuesta3

A continuación se muestra un ejemplo de uso del editor Vim/Ex desde la línea de comandos para un patrón:

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

Para patrones múltiples, repita con comandos adicionales, agregue un bucle o realice un bucle desde el shell, por ejemplo

$ 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.}

Usar solo Shell para analizar los datos es mucho más simple, por ejemplo:

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

Para varias líneas:

$ 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.}

información relacionada