Удалить определенный символ из следующей строки в той же позиции (ах)?

Кажется, ваш пример взят из страниц руководства.

MAN изначально проектировался как телетайп. Для жирного шрифта последовательность будет XX. Вероятно, потерялись при выводе в редактор, отсюда и двойные символы.

vi может легко удалить их.

См .: https://stackoverflow.com/questions/26634497/redirecting-man-page-output-to-file-results-in-double-letters-in-words

3
28.04.2018, 14:03
5 ответов

Это довольно легко сделать в awk. Когда вы увидите #, определите, где в строке он находится. Затем для этой строки и всех последующих строк вырезать эту позицию символа из строки.

awk '
    /#/ { pound=index($0, "#") }
        {
                if (pound)
                        print substr($0, 1, pound-1) substr($0, pound+1)
                else
                        print
        }
    '
0
27.01.2020, 21:18

С помощью sed это можно сделать следующим образом. Поместите два маркера в начале двух линий, предварительно переместив их в пространство шаблона.

Затем начните перемещать их вправо по символу за раз. Во время этого движения обратите внимание на то, что находится справа от маркеров, и примите соответствующие меры.

Остановиться, когда маркер достигнет конца пространства шаблона. Теперь уберите маркеры, так как их работа сделана, и останется то, что вам нужно. Обратите внимание на маркер \n

 sed -Ee '
   /#/N;/\n/!b
   s/\n/&&/;s/^/\n/
   :a
       /\n#(.*\n.*\n)./{
          s//\n\1/;ba
       }
      s/\n(.)(.*\n.*)\n(.)/\1\n\2\3\n/
   /\n$/!ba
   s/\n//;s///2
'    input

Использование Perl решается следующим образом:

 perl -pe  ' 
     next unless /#/;

     my($n,$p) = (scalar <>);

     while ( /#/g ) {
        pos($n) = pos() - 1 - $p++;
        $n =~ s/\G.//;
     }

     y/#//d;s/\z/$n/;
'      input_file 

Рабочий:

1. Skip lines that donot have hash char.
 2. Save the next line in $n and init. $p counter which keeps track of the number of hash chars erased till now.
3.  Monitor the position of the hash char in a while loop and using info generate the position of the char to be deleted in next line.
4.  Erase it using the \G metachar in s///
5.  In the final step remove the hash chars from present line and append the next line to it.

Показан другой метод, на этот раз использующий массивы:

perl -aF'' -ne '
    print,next unless /#/;
    print,last if eof;

    my @I = grep { $F[$_] ne "#" } 0.. $#F;
    my @N = split //, <>;

    print @F[@I], @N[@I];
'    input_file

Рабочий:

1. Invoke Perl to split each line on a per character basis and have it stored in the array @F anew for every line read.
2.  Record the array indices for which the array element is a non hash character.
3.  Readin the next line, split it on a per character basis and store in array @N.
4. Now its a matter of selecting the indices we stored in @I and fetch those from arrays @F and @N.

Метод регулярных выражений:

perl -pe '
   $_.= <> unless eof;

    s/\G.(.*\n.{@{[+pos]}})./$1/ while /(?=#.*\n.)/g;
'        input_file

Описание:

° добавить следующую строку к текущей, если это не последняя строка.

° Запишите позиции символов решетки в первой строке с помощью цикла while.

° Затем удалите символ решетки в исходной строке и символ в соответствующей позиции в следующей строке.

° После выхода из цикла while опция -p автоматически выведет $ _на стандартный вывод.

Метод с простыми строковыми операциями:

perl -pe '
   last if eof;
   my $n = <>;
   while ( (my $p = index($_,"#")) > -1 ) {
      substr($_, $p, 1) = "" for $_, $n;
   }
   $_.= $n;
'       input_file

Это включает в себя использование встроенного индекса для проверки позиции хэша, а затем его использование во встроенной подстроке два раза... в первой и следующей строках.

2
27.01.2020, 21:18

авк

Эти методы повторяются для каждой пары строк (1 и 2; 3 и 4; etc ), обрабатывая столько #символов, сколько есть в первой строке каждой пары, и предполагая, что две строки каждой пары имеют одинаковую длину.

Совместимость с GNU awk (Linux )и BSD awk (Mac ).


Использование подстрок:

awk '{ a=$0 ; gsub(/#/,"",$0) ; print $0 ; getline ; for (n=1;n<=length(a);n++) if ( substr(a,n,1) != "#" ) printf "%s",substr($0,n,1) ; printf "%s",RS }' file.txt

Тот же код, переформатированный для более узких экранов:

awk '{
  a=$0 ;
  gsub(/#/,"",$0) ;
  print $0 ;
  getline ;
  for (n=1;n<=length(a);n++)
    if ( substr(a,n,1) != "#" )
      printf "%s",substr($0,n,1) ;
  printf "%s",RS
  }' file.txt
  • a=$0
    Сохраните копию первой строки.
  • gsub(/#/,"",$0) ; print $0
    Удалить все #из первой строки (, а не из копии ), затем распечатать измененную первую строку.
  • getline
    Перейти к следующей строке.
  • for (n=1;n<=length(a);n++)
    Перебрать каждый символ первой копии строки -.
    • if ( substr(a,n,1) != "#" )
      Если эта единственная символьная подстрока -не является #,…
      • printf "%s",substr($0,n,1)
        …затем напечатать символ с соответствующей позиции во второй строке.
  • printf "%s",RS
    Завершите вторую строку символом новой строки.

Использование массивов:

awk '{ c=d="" ; elements=split($0,a,"") ; getline ; split($0,b,"") ; for (n=1;n<=elements;n++) if (a[n]!="#") { c = c a[n] ; d = d b[n] } ; print c ; print d }' file.txt

Переформатирован для более узких экранов:

awk '{
  c=d="" ;
  elements=split($0,a,"") ;
  getline ;
  split($0,b,"") ;
  for (n=1;n<=elements;n++)
    if (a[n]!="#")
      { c = c a[n] ; d = d b[n] } ;
  print c ;
  print d
  }' file.txt
  • c=d=""
    Инициализировать две пустые строки. Они станут модифицированными версиями двух строк ввода. Этот шаг необходим, если имеется более двух строк ввода.
  • elements=split($0,a,"")
    Преобразование первой строки ввода в массив с одним символом на элемент массива. Сохраните количество элементов массива как переменную elements.
  • getline
    Перейти к следующей строке.
  • split($0,b,"")
    Преобразование второй строки ввода в массив с одним символом на элемент массива.
  • for (n=1;n<=elements;n++)
    Пройдитесь по каждому элементу первого -линейного массива.
    • if (a[n]!="#")
      Если этот единственный элемент массива символов -не является #,…
      • { c = c a[n] ; d = d b[n] }
        …затем для каждой из двух строк сохраните символ из позиции n.
  • print c ; print d
    Распечатать новые версии двух строк.

Внимание:Версия awk для Mac (BSD )не обрабатывает элементы массива автоматически в порядке номеров. Сначала это дало мне удивительные результаты.

The order in which a ‘for (indx in array)’ loop traverses an array is undefined in POSIX awk and varies among implementations. gawk lets you control the order by assigning special predefined values to PROCINFO["sorted_in"].

The GNU Awk User’s Guide

Элементы по-прежнему нумеруются 1,2,3,...во время создания с помощью split, как и в GNU awk, но BSD awk не обязательно видит их в таком порядке при использовании for (n in array). Таким образом, вы получите зашифрованную тарабарщину.

Чтобы обойти это, вы можете сохранить длину массива (количество элементов )при создании массива — например, elements=split($0,a,"")— и затем перебирать элементы, используя for (n=1;n<=elements;n++), как я' я сделал здесь.


Пример ввода(file.txt):

abcdb#lae#blabl#a
abc~bola~xblabl~a
#alpha#beta#gamma#delta#epsilon#
abcdefghijklmnopqrstuvwxyzabcdef

Пример вывода:

abcdblaeblabla
abc~bla~blabla
alphabetagammadeltaepsilon
bcdefhijkmnopqstuvwyzabcde
2
27.01.2020, 21:18
awk '{gsub(/#/,"")sub(/bola~x/,"bla~")sub(/~a$/,"a")}1' file

output
abcdblaeblabla
abc~bla~blabla
0
27.01.2020, 21:18

С помощью gnu awk с использованием gensub

awk '
/#/{
  a=$0
  b=length()
  getline
  $0=a RS$0
  while($0!=a){
    a=$0
    $0=gensub("([^#]*)#(.{"b--"}).","\\1\\2",1)}
}1' infile

Объяснить:

/ #/ :для каждой строки с#

a=$0 :сохранить строку в a

b=длина():получить длину в b

getline :получить следующую строку

$0=a RS$0 :добавить предыдущую строку, хранящуюся в a, в начало буфера $0, за которым следует RS в качестве разделителя записей

Теперь $0 содержит 2 строки

в то время как ($0!=a):в то время как строка, хранящаяся в a, отличается от буфера $0

a=$0 :получить буфер $0 в a

$0=gensub (" ([^ #] *)#(.{"b --"} ).","\\1\\2",1):удалите первый #в $0 и соответствующий символ во второй строке

Одновременно уменьшить (b --)длину первой строки на 1, потому что 1 #было удалено

1 :когда в первой строке больше нет #выведите $0

0
27.01.2020, 21:18

Теги

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