sed: заменить n-е слово на соответствующий шаблон? - PullRequest
5 голосов
/ 16 февраля 2012

У меня есть текстовый файл со следующими характеристиками:

  1. каждая строка содержит как минимум три слова, разделенных пробелом
  2. слово может быть любым символом илистрока символов

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

NO NO O
SIGNS NN O      #NNS
GIVEN VBD B-VP  #VBN
AT IN O
THIS NN O       
TIME NN O            ## B-NP
. PER O
...

Примечания с 1 # заменяют ВТОРОЕ слово в строке, а примечания с 2 # заменяют ТРЕТЬЕ словов линии.Кто-нибудь сможет предложить способ сделать это с помощью sed (или awk, или чего-то еще)?Опять же, чтобы уточнить (надеюсь), моя цель - получить шаблон, следующий за # или ##, и заменить n-е слово строки соответствующим шаблоном.

Спасибо.

Ответы [ 3 ]

4 голосов
/ 16 февраля 2012

Это будет работать для вас:

awk '/#/{sub(/# +/,"#");n=gsub(/#/,"",$NF);$(n+1)=$NF;$NF="\t\t#"}1' file

Объяснение

  1. /#/{ ... }: поиск строк, содержащих #, и выполнение следующих шагов ...
  2. sub(/# +/,"#"): убрать все пробелы между нотами и #, если необходимо
  3. n=gsub(/#/,"",$NF): убрать все # из последнего поля $NF и установить число # удалены в переменную n
  4. $(n+1)=$NF: установите в поле n + 1 $(n+1) новое последнее поле $NF, в котором все # удалены
  5. $NF="\t\t#": установите в последнем поле $NF две вкладки, за которыми следует #
  6. 1: ярлык для указания awk на печать измененной строки
  7. file: Ваш входной файл

Пример

$ awk '/#/{sub(/# +/,"#");n=gsub(/#/,"",$NF);$(n+1)=$NF;$NF="\t\t#"}1' file
NO NO O
SIGNS NNS O             #
GIVEN VBN B-VP          #
AT IN O
THIS NN O
TIME NN B-NP            #
. PER O
...

Примечание : Если вы сделаете так, ваши заметки всегда будут следовать1048 * с пробелами между ними, вы можете удалить всю sub(/# +/,"#"); часть команды, чтобы сделать ее еще короче

1 голос
/ 16 февраля 2012

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

sed 's/\S*\(\s*\S*\s*#\s*\)\([^#]*\)$/\2\1/;s/ *##*.*/\t\t#/' file
NO NO O
SIGNS NNS O             #
GIVEN VBN B-VP          #
AT IN O
THIS NN O       
TIME NN B-NP            #
. PER O
...
0 голосов
/ 16 февраля 2012

Perl может справиться с этим. Хотя я думаю, что предпочел бы сделать это сценарием.

Вставить версию:

perl -lnwe 's/#\K\s+//; my @a=/\S+/g; if (@a>3) { $c = $a[3] =~ tr/#//d; $a[$c] = $a[3]; } print join " ", @a[0..2]' file

Эта версия будет распечатана на стандартный вывод и не изменит файл. Добавить -i.bak, например perl -i.bak -lnwe '....' для редактирования на месте с резервным копированием в file.bak.

Версия для чтения:

$ perl -lnwe '       # -l: handle newlines, -n read file/stdin
    s/#\K\s+//;                    # strip optional spaces
    my @a = /\S+/g;                # extract the data
    if (@a > 3) {                  # when there are replacements..
        my $c = $a[3] =~ tr/#//d;  # count and remove #
        $a[$c] = $a[3];            # set element number $c to element 3
    } print join " ", @a[0..2]     # reassemble and print 3 first elements
' file

Выход:

NO NO O
SIGNS NNS O
GIVEN VBN B-VP
AT IN O
THIS NN O
TIME NN B-NP
. PER O
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...