сопоставить повторяющийся символ в sed на mac - PullRequest
0 голосов
/ 02 мая 2018

Я пытаюсь найти все экземпляры 3 или более новых строк и заменить их только 2 новыми строками (представьте файл со слишком большим пробелом). Я использую sed, но хорошо с ответом, используя awk или тому подобное, если это проще.

note : я на Mac, поэтому sed немного отличается от Linux (BSD против GNU)

Моя настоящая цель - новые строки, но я не могу заставить ее работать вообще, поэтому для простоты я пытаюсь сопоставить 3 или более повторений bla и заменить это на BLA.

Создайте файл примера с именем stupid.txt:

$ cat stupid.txt

blablabla
$

Насколько я понимаю, вы соответствуете i или нескольким вещам с использованием синтаксиса регулярных выражений thing{i,}.
Я попробовал варианты этого, чтобы соответствовать 3 bla с без удачи:

cat stupid.txt | sed 's/bla{3,}/BLA/g'      # simplest way
cat stupid.txt | sed 's/bla\{3,\}/BLA/g'    # escape curly brackets
cat stupid.txt | sed -E 's/bla{3,}/BLA/g'   # use extended regular expressions
cat stupid.txt | sed -E 's/bla\{3,\}/BLA/g' # use -E and escape brackets

Теперь у меня нет идей, что еще попробовать!

Ответы [ 4 ]

0 голосов
/ 02 мая 2018

Чтобы сохранить только 2 новых строки, вы можете попробовать это sed

sed '
  /^$/!b
  N
  /../b
  h
  :A
  y/\n/@/
  /^@$/!bB
  s/@//
  $bB
  N
  bA
  :B
  s/^@//
  /./ {
    x
    G
    b
  }
  g
' infile

/ ^ $ /! B Если это пустая строка, не печатайте ее

N получить новую строку

/ .. / b, если эта новая строка не пуста, выведите 2 строки

h хранит 2 пустые строки в буфере удержания

: этикетка A

На данный момент в буфере паттернов всегда есть 2 строки, а первая пуста

y / \ n / @ / заменить \ n на @ (вы можете выбрать другой символ, которого нет в вашем файле)

/ ^ @ $ /! BB Если вторая строка не пуста, переходите к B

s / @ // удалить @

$ bB Если последняя строка, переходите к B

На данный момент в шаблонном пространстве есть 1 пустая строка

N получить последнюю строку

bA перейти к A

: метка B B

s / ^ @ // удалить символ @ в начале строки

/. / {Если последняя строка не пуста

x шаблон обмена и удержание буфера

G добавить буфер удержания в пространство паттернов

b перейти к концу

}

g заменить пространство шаблона (пустое) на пространство удержания

печать пробела

0 голосов
/ 02 мая 2018
sed -E 's/bla{3,}/BLA/g' 

Вышеуказанное соответствует bl, за которым следуют три или более повторов a. Это не то, что вы хотите. Похоже, что вы действительно хотите три или более повторений bla. Если это так, то замените:

$ sed -E 's/bla{3,}/BLA/g' stupid.txt
blablabla

С:

$ sed -E 's/(bla){3,}/BLA/g' stupid.txt
BLA

Вышеприведенное, тем не менее, напрямую не помогает в вашей задаче замены символов новой строки, поскольку по умолчанию sed читает только одну строку за раз.

Замена новых строк

Давайте рассмотрим этот файл, в котором есть 3 перевода строки между 1 и 2:

$ cat file.txt

1



3

Чтобы заменить любое вхождение трех или более символов новой строки одной строкой:

$ sed -E 'H;1h;$!d;x; s/\n{3,}/\n/g' file.txt

1
3

Как это работает:

  • H;1h;$!d;x

    Эта сложная серия команд читает весь файл. Это наверное Проще всего думать об этом как идиома. Если вы действительно хотите знать кровавые детали:

    • H - добавить текущую строку в качестве пробела
    • 1h - Если это первая строка, перезаписать пробел с этим
    • $!d - Если это не последняя строка, удалить пробел и перейти к следующей строке.
    • x - обмен удержанием и шаблоном для помещения всего файла шаблонное пространство
  • s/\n{3,}/\n/g

    Заменяет все последовательности трех или более символов новой строки одним символом новой строки.

Alternate

Приведенное выше решение считывает сразу весь файл. Для больших (гигабайтных) файлов это может быть недостатком. Этот альтернативный подход позволяет избежать:

$ sed -E '/^$/{:a; N; /\n$/ba; s/\n{3,}([^\n]*)/\1/}' file.txt # GNU only

1
3

Как это работает:

  • /^$/{...}

    Выбирает пустые строки. Для пустых и только пустых строк выполняются команды в фигурных скобках:

  • :a

    Это определяет метку a.

  • N

    Это читает следующую строку из файла в пространство шаблона, отделенное от предыдущего новой строкой.

  • /\n$/ba

    Если последняя прочитанная строка пуста, переходите к метке a.

  • s/\n{3,}([^\n]*)/\1/

    Если мы не выполняли ветвление, выполняется подстановка, которая удаляет лишние символы новой строки.

Версия BSD : У меня нет системы BSD, чтобы проверить это, но я предполагаю:

sed -E -e '/^$/{:a' -e N -e '/\n$/ba' -e 's/\n{3,}([^\n]*)/\1/}' file.txt
0 голосов
/ 02 мая 2018

Если приемлем весь файл slurping:

perl -0777pe 's/(\n){3,}/\n\n/g' newlines.txt

Где вы должны заменить \n любой последовательностью новой строки.

-0777 говорит Perl не разбивать каждую строку на свою собственную запись, что позволяет регулярному выражению, которое работает через строки, функционировать.

Если вы удовлетворены результатом, -i заставляет perl заменить файл на месте, а не выводить на стандартный вывод:

perl -i -0777pe 's/(\n){3,}/\n\n/g' newlines.txt

Вы также можете сделать следующее: -i~ создать файл резервной копии с заданным суффиксом (в данном случае ~).

Если не использовать весь файл не приемлемо:

perl -ne 'if (/^$/) {$i++}else{$i=0}print if $i<3' newlines.txt

Печатает любую строку, которая не является третьей (или более высокой) последовательной пустой строкой. -i работает с этим так же.

ps - MacOS поставляется с установленным Perl.

0 голосов
/ 02 мая 2018

thing{3,} соответствует thinggg. Используйте (..) для группировки вещей, чтобы квантификатор применялся к тому, что вы хотите:

$ echo blablabla | sed -E 's/(bla){3}/BLA/g'
BLA
...