Найдите ключевое слово в файле, а затем добавьте строку после нахождения ключевого слова в теле, используя perl или sed - PullRequest
0 голосов
/ 17 сентября 2018

Я пытался найти ключевое слово (ячейка (edita)) в длинном файле (input.txt), который содержит более 10000 строк и разных имен ячеек, таких как ячейка (noedit), ячейка (editb). для контакта (q) (2-й случай) добавьте строку «класс», контакт (yz) (2-й случай) и добавьте «доску». Я не должен манипулировать блоком ячейки (noedit) .

МОЙ input.txt

        cell (edita)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
        cell (noedit)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
    cell (editb)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }

мой output.txt должен выглядеть так

cell (edita)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 "class";
                 add
                 }
                 pin (yz) {
                 board;
                 add 
             }
        }
        cell (noedit)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
    cell (editb)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 "class";
                 add
                 }
                 pin (yz) {
                 board ;
                 add 
             }
        }

Я попытался написать sed, который работает только в том случае, если файл имеет контактный вывод (т. Е. Нет строки cell (a)), и даже он манипулирует только вторым вхождением

sed '/\spin\s(Q)/ enjp;s/./1/;H;g;/^(\n1) enj2 broadcast$/s// class ; / p; d} 'input.txt sed '/\spin\s(y)/ enjp;s/./1/;H;g;/^(\n1) enj2 coming$/s// board; / p ; d} 'input.txt

Пожалуйста, кто-нибудь может помочь мне найти клетку и затем манипулировать.

Заранее спасибо

Ответы [ 4 ]

0 голосов
/ 17 сентября 2018

Если у вас более 1 блока с ячейкой (а) ...

awk '
  function addline(ind, value) {
    if(++a[ind]==2) { 
      b=$0
      sub(/[^[:blank:]].*/,"",b)
      $0=$0 "\n" b value " ;"
    }
  }
  /^cell/ {
    split("",a)
    f=0
    if(/(a)/)
      f=1
  }
  $0 ~ "pin [(]Q[)]" && f {
    addline("Q", "class")
  }
  $0 ~ "pin [(]y[)]" && f {
    addline("y", "board")
  }
1' input.txt
0 голосов
/ 17 сентября 2018

idk о perl, но sed предназначен для выполнения s / old / new , то есть всего , а для всего остального стандартным инструментом UNIX является awk для ясности, простоты, эффективности, переносимости и т. Д. И т. Д. И т. Д. Из вашего примера похоже, что это все, что вы пытаетесь сделать:

$ cat tst.awk
BEGIN {
    map["pin (Q)"] = "class ;"
    map["pin (y)"] = "board ;"
}
{ print }
$1 == "cell" { cell = "$2" }
cell == "(a)" {
    for (pin in map) {
        if ( (s=index($0,pin)) && (++cnt[pin]==2) ) {
            print substr($0,1,s-1) map[pin]
        }
    }
}

$ awk -f tst.awk file
cell (a)  {
    test{
         pin (Q) {
         zzzzzz
        }
        pin (y) {
        zzzzz
        }
        }
         pin (Q) {
         class ;
         add
         }
         pin (y) {
         board ;
         add
     }
}

Если это не так, отредактируйте ваш вопрос, чтобы уточнить ваши требования и предоставить более по-настоящему репрезентативные выходные данные.

Я вижу из вашего комментария в ответе @ potong, что вы хотите добавить 3-й пин - чтобы сделать это в вышеприведенном скрипте, вы просто добавляете новое отображение в соответствии с существующими 2 map[] назначениями:

BEGIN {
    map["pin (Q)"] = "class ;"
    map["pin (y)"] = "board ;"
    map["pin (z)"] = "board2 ;"
}
0 голосов
/ 17 сентября 2018

Решение Perl.Это работает как фильтр Unix.Так что, если он находится в файле с именем transform, вы бы запустили его как:

$ transform < input.txt > output.txt

Вот код:

#!/usr/bin/perl

use strict;
use warnings;

my $in_cell_a;
my $brace_level = 0;
my ($pin_q, $pin_y);

while (<>) {
  print;
  if (/{/) {
    $brace_level++;
  }
  if (/cell \(a\)/) {
    $in_cell_a = $brace_level;
  }
  if (/(\s*)pin \(Q\)/) {
    if ($pin_q) {
      print "${1}class ;\n";
      $pin_q = 0;
    } else {
      $pin_q = 1;
    }
  }
  if (/(\s*)pin \(y\)/) {
    if ($pin_y) {
      print "${1}board ;\n";
      $pin_y = 0;
    } else {
      $pin_y = 1;
    }
  }

  if (/}/) {
    if ($brace_level == $in_cell_a) {
      $in_cell_a = 0;
    }
    $brace_level--;
  }
}

Обновление: Вот обновленныйверсия, которая использует более управляемый данными подход.Чтобы добавить дополнительные преобразования, вам просто нужно добавить их в переменную $fix.

#!/usr/bin/perl

use strict;
use warnings;

my $in_edit_block;
my $brace_level = 0;

my $fix = {
  'pin (Q)' => "class ;\n",
  'pin (y)' => "board ;\n",
};

my $flag;

my $fix_re = join '|', map { "\Q$_\E" } keys %$fix;

while (<>) {
  print;
  if (/{/) {
    $brace_level++;
  }
  if (/\Qcell (a)/) {
    $in_edit_block = $brace_level;
  }
  if ($in_edit_block) {
    if (my ($pad, $match) = /(\s*)($fix_re)/) {
      if ($flag->{$match}) {
        print "${pad}$fixes->{$match}";
        $flag->{$match} = 0;
      } else {
        $flag->{$match} = 1;
      }
    }
  }

  if (/}/) {
    if ($brace_level == $in_edit_block) {
      $in_edit_block = 0;
    }
    $brace_level--;
  }
}
0 голосов
/ 17 сентября 2018

Это может работать для вас (GNU sed):

sed '1{x;s/^/;,/;x};/^cell (a)/I,/^}/{/pin (q)/I{x;s/;/&q/;/;q\{2\},/{x;p;s/pin.*/class ;/;x};x};/pin (y)/I{x;s/,/&y/;/,y\{2\}$/{x;p;s/pin.*/board ;/;x};x}}' file

Заполнить пространство удержания парой разделителей (; для pin (q) счетчика и , для pin (y) счетчика),Ограничить обработку до cell (a).Каждый раз, когда встречается pin (q) или pin (y), добавляйте его к соответствующему счетчику в области удержания.Если счетчик равен 2 (может быть любым числом), напечатайте текущую строку, а затем измените текущую строку, чтобы отразить добавленную строку.

РЕДАКТИРОВАТЬ: Поскольку первоначальный вопрос изменился:

sed '/cell ([^)]*)/{h;x;s/^/;:,/;x};G;/cell (edit[ab])/{/pin (q)/I{x;s/;/&q/;/;q\{2\}:/{x;P;s/\S.*/"class";/;x};x};/pin (yz)/I{x;s/:/&y/;/:y\{2\},/{x;P;s/\S.*/board/;x};x}};P;d' file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...