¿Cómo agregar alguna línea coincidente con la línea anterior emparejada con sed?


4

Por ejemplo, transfiera a continuación

00:00:10.730
this presentation is delivered by the

00:00:13.230
Stanford center for professional

00:00:14.610
development okay so let's get started

00:00:25.500
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

a

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

¿Usa algo como gaupol para mezclar subtítulos?
Satō Katsura

Respuestas:


2

En aras de la claridad del código, estamos utilizando GNU sed:

sed -nE '

   /^([0-9][0-9]:){2}[0-9]+[.][0-9]+/!{p;d;}

   h;:a
      $bb;n;H
   /^([0-9][0-9]:){2}[0-9]+[.][0-9]+/!ba

   :b
   x
   y/\n_/_\n/
   s/^([^_]*)_(.*)_([^_]*)$/\1 ---> \3_\2/
   y/\n_/_\n/

   p;g;$!s/^/\n/;D

' yourfile

Resultados

00:00:10.730 ---> 00:00:13.230
this presentation is delivered by the

00:00:13.230 ---> 00:00:14.610
Stanford center for professional

00:00:14.610 ---> 00:00:25.500
development okay so let's get started

00:00:25.500 ---> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

Explicación

  • Mantenemos un rango de líneas desde el número hasta el siguiente número.
  • Luego, al final del rango, se avanza la última parte y se imprime el rango, también se borra el espacio del patrón y se usa el final del rango para llenarlo y luego, usando este valor del espacio del patrón, el control se transfiere a la parte superior de código sed para comenzar de nuevo el ciclo desde el final actual del rango hasta el siguiente número o hasta que lleguemos al eof.

1

Con un enfoque de gawk único para archivos relativamente "pequeños" (por tamaño):

awk 'BEGIN{ RS=""; FS="[[:space:]]+" }
     {   c++; 
         a[c]["t"]=$1; 
         a[c]["s"]=substr($0,length($1)+2) 
     }
     END { 
         len=length(a); 
         for(i=1;i<=len;i++) { 
             if((i+1)<=len){ printf("%s --> %s\n%s\n\n",a[i]["t"],a[i+1]["t"],a[i]["s"]) } 
             else { printf("%s\n%s\n",a[i]["t"],a[i]["s"]) }
         } 
     }' file

La salida:

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

Esto carga todo el archivo en la memoria.
Satō Katsura

@SatoKatsura, agregó una nota a mi respuesta. Podría usarse para archivos "pequeños"
RomanPerekhrest

1

Con GNU sedy tac:

tac file | \
sed -E '/^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}$/ { H; x; s/^\n//; s/\n/ --> /; }' | \
tac

Lo mismo podría escribirse con tradicional sed(es decir, sin -E), pero sería más detallado.

Con GNU awky tac:

tac file | \
gawk --re-interval '
    /^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3} --> / { old = $1 }
    /^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}$/ { if(old != "") $0 = $0 " --> " old; old = $1 }
    1' | \
tac

Tenga en cuenta que la awkversión puede manejar intervalos de tiempo como 00:00:14.610 --> 00:00:25.500en el archivo de entrada, mientras que la sedversión es engañada por ellos.

Tenga en cuenta también que tacse puede emular con sed:

sed -n '1!G; $p; h'

o así:

sed '1!G; h; $!d'

Sin embargo, ambos formularios cargarán todo el archivo de entrada en la memoria, por lo que no son muy eficientes.

Resultado:

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

0

Veo bucles o tuberías a otras herramientas en las respuestas dadas, y no me gusta eso si no es necesario. Me gustan las frases sencillas:

sed -E '/^[0-9:.]+$/{x;G;s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/p;d;};H;$!d;x'

Pero vamos paso a paso:

  • Utilizo ^[0-9:.]+$como expresión regular extendida para la línea de marca de tiempo. Esto debería ser suficiente en el mundo real, pero siéntase libre de hacerlo más preciso. Utilizo este patrón como una dirección, por lo que todo dentro del {}par se ejecuta solo para las líneas de marca de tiempo.
  • Obviamente, debemos tener todo en mente hasta que llegue la siguiente marca de tiempo. Tener en cuenta significa agregar al espacio de espera ensed
  • Por lo tanto, cada vez que nos encontramos con una marca de tiempo, asumimos todo, ya que la última marca de tiempo reside en el espacio de espera. Por lo tanto, agregamos la marca de tiempo actual al Hespacio anterior y xcambiamos el patrón y mantenemos el espacio. De esta manera, la marca de tiempo actual ya está guardada en el espacio de espera para el siguiente ciclo, mientras que todo lo que necesitamos está en el espacio del patrón
  • Solo necesitamos reorganizarlo con substitute: s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/- \1es la marca de tiempo de inicio, \2es la línea de texto, \3es una nueva línea (la necesitamos en el reemplazo, pero POSIX no define \nen el reemplazo) y \4es la marca de tiempo de finalización. Parece más complicado de lo que es.
  • Agregar una opción pa la subicación y luego delegir el espacio del patrón nos evita la salida no deseada para la primera línea cuando el espacio de espera todavía estaba vacío.
  • Ahora todo lo que queda es agregar otras líneas al Hespacio anterior y
  • para la última línea e xcambie de nuevo los búferes, de modo que las líneas recogidas en el espacio de espera se imprimirán incluso sin cerrar la marca de tiempo

Si alguien todavía siente sedque no es elegante, no puedo evitarlo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.