Как добавить строку, соответствующую предыдущей строке, соответствующей sed?

Думаю, вы неправильно поняли условные выражения awk . Начало каждой строки - это условие. Это более ... awk способ сделать это: А как насчет

awk '
/LY1/ { 
        tag=gensub(/_.*/,"","1",gensub(/.*LY1/,"LY1","1", $NF))
        print tag
        next
}
{
    print
}' input.file

Первое / LY1 / является неявным совпадением -условием - он выполняет выражение только в том случае, если строка ввода соответствует этому регулярному выражению. Выражение начинается с замены всего в этой строке, вплоть до LY1 на LY1 , и помещает это в тег переменной. Затем он печатает тег, и оператор next пропускает все остальные выражения для этой записи .

После этого следует безусловное выражение, которое просто печатает строку как есть - но это не будет выполнено, если предыдущее выражение было выполнено, поскольку это вызвало бы next .

4
08.06.2017, 14:34
4 ответа

С одним подходом gawk для относительно "небольших" (по размеру) файлов:

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

Вывод:

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
1
27.01.2020, 20:55

С GNU sedиtac:

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

То же самое можно было бы написать и с традиционным sed(, т.е. без -E), но это было бы более многословно.

С GNU awkи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

Обратите внимание, что версия awkможет обрабатывать временные интервалы, такие как 00:00:14.610 --> 00:00:25.500, во входном файле, в то время как версия sedих обманывает.

Также обратите внимание, что tacможно эмулировать с помощью sed:

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

или вот так:

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

Однако обе формы будут загружать весь входной файл в память, поэтому они не очень эффективны.

Результат:

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
1
27.01.2020, 20:55

Для ясности кода мы используем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

Результаты

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

Пояснение

  • Мы сохраняем диапазон строк от номера к следующему номеру.
  • Затем, в конце диапазона, последняя часть выдвигается вперед и печатается диапазон, также пространство шаблона очищается, и конец диапазона используется для его заполнения, а затем, используя это значение пространства шаблона, управление передается в начало кода sed для запуска цикла заново с текущего конца диапазона до следующего числа или до тех пор, пока мы не нажмем eof.
2
27.01.2020, 20:55

В приведенных ответах я вижу циклы или переходы к другим инструментам, и мне это не нравится, если в этом нет необходимости. Мне нравится один -вкладыш:

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

Но давайте шаг за шагом:

  • Я использую ^[0-9:.]+$как расширенное регулярное выражение для строки метки времени. Этого должно быть достаточно в реальном мире, но вы можете сделать это более точным. Я использую этот шаблон в качестве адреса, поэтому все внутри пары {}выполняется только для строк с метками времени.
  • Очевидно, нам нужно держать все в голове, пока не придет следующая метка времени. Иметь в виду означает добавлять к пространству хранения вsed
  • Таким образом, каждый раз, когда мы встречаем метку времени, мы предполагаем все, поскольку последняя метка времени находится в пространстве хранения. Таким образом, мы добавляем текущую метку времени к Hстарому пробелу и e xменяем шаблон и удерживаем пробел. Таким образом, текущая временная метка уже сохраняется в пространстве хранения для следующего цикла, а все, что нам нужно, находится в пространстве шаблонов
  • .
  • Нам просто нужно реорганизовать его с помощью sзаменить:s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/--\1начальную метку времени, \2текстовую строку, \3новую строку (нам нужно это в замене, но POSIX не t определите \nвместо ), а \4— отметку времени окончания. Выглядит сложнее, чем есть.
  • Добавление опции pк замене sи последующее dудаление пространства шаблона предохраняет нас от нежелательного вывода для первой строки, когда пространство удержания было пустым.
  • Теперь все, что осталось, это добавить другие строки к старому пространству Hи
  • для последней строки e xснова измените буферы, поэтому строки, собранные в области хранения, будут напечатаны даже без метки времени закрытия

Если кто-то по-прежнему считает sedнеэлегантным, я ничем не могу помочь.

0
27.01.2020, 20:55

Теги

Похожие вопросы