AWK: перенос строк до 72 символов

7
$ awk 'length > 72' {HOW TO PRINT THE LINEs IN PCS?} msg

то есть я хочу добавить \nпосле 72 символов и продолжить, поэтому сначала вам может понадобиться удалить все одиночные \nбуквы и добавить их. Может быть проще с другим инструментом, но давайте попробуем awk.

[Обновить]

Уильямсон дал правильный ответ, но для его прочтения понадобилась помощь. Я разбил проблему на части с более простыми примерами ниже.

  1. Почему код ниже печатается \tв обоих случаях, gsubдолжны заменить вещи? x - фиктивный файл, в конце нечетный 0.

  2. Нападая на строку line = $0 \n more = getline \n gsub("\t"," ")в ответе Уильямсона , lineочевидно, получает полный вывод, в то время как moreполучает повышенное значение $0, верно?

Код к части 1

$ gawk '{ hallo="tjena\t tjena2"; gsub("\t"," "); }; END {print hallo; gsub("\t", ""); hallo=hallo gsub("\t",""); print hallo }' x
tjena  tjena2
tjena  tjena20
Сообщество
источник

Ответы:

4

Вот скрипт AWK, который переносит длинные строки и перезаписывает остатки, а также короткие строки:

awk -v WIDTH=72 '
{
    gsub("\t"," ")
    $0 = line $0
    while (length <= WIDTH) {
        line = $0
        more = getline
        gsub("\t"," ")
        if (more)
            $0 = line " " $0
        else
            $0 = line
            break
    }
    while (length >= WIDTH) {
        print substr($0,1,WIDTH)
        $0 = substr($0,WIDTH+1)
    }
    line = $0 " "
}

END {
    print
}
'

На CPAN доступен Perl-скрипт, который отлично справляется с переформатированием текста. Это называется paradj ( отдельные файлы ). Для того, чтобы сделать переносы, вам также понадобится TeX::Hyphen.

SWITCHES
--------
The available switches are:

--width=n (or -w=n or -w n)
    Line width is n chars long

--left (or -l)
    Output is left-justified (default)

--right (or -r)
    Output is right-justified

--centered (or -c)
    Output is centered

--both (or -b)
    Output is both left- and right-justified

--indent=n (or -i=n or -i n)
    Leave n spaces for initial indention (defaults to 0)

--newline (or -n)
    Insert blank lines between paragraphs

--hyphenate (or -h)
    Hyphenate word that doesn't fit on a line

Вот разница некоторых изменений, которые я сделал, чтобы поддержать опцию левого поля:

12c12
< my ($indent, $newline);
---
> my ($indent, $margin, $newline);
15a16
>   "margin:i" => \$margin,
21a23
> $margin = 0 if (!$margin);
149a152
>     print " " x $margin;
187a191,193
>   print "--margin=n (or -m=n or -m n)  Add a left margin of n ";
>   print "spaces\n";
>   print "                                (defaults to 0)\n";
Приостановлено до дальнейшего уведомления.
источник
Кстати, я снял сценарий Жиля, чтобы использовать его как часть своего.
Приостановлено до дальнейшего уведомления.
13

Не используя awk

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

fmtИнструмент был разработан с конкретно это в виду:

fmt --width=72 filename

fmtтакже постараюсь разбить строки в разумных местах, делая вывод более приятным для чтения. Смотрите infoстраницу для более подробной информации о том, что fmtсчитает "разумные места".

Стивен Д
источник
GNU fmt не поддерживает многобайтовые кодировки, то widthесть байты, а не символы.
Филипп Ковалев
4
Пользователи MacOS могут использоватьfold -s -w 72
Эдвард Лаволл
@EdwardLoveall foldбудет работать и на системах GNU (поставляется с GNU coreutils).
heemayl
3

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

awk -v WIDTH=72 '
{
    while (length>WIDTH) {
        print substr($0,1,WIDTH);
        $0=substr($0,WIDTH+1);
    }
    print;
}
'

Если вы хотите обрезать строки между словами, вы можете закодировать их в awk, но распознавать слова нетривиально (по причинам, связанным больше с естественными языками, чем с алгоритмическими сложностями). Во многих системах есть утилита, fmtкоторая делает это.

Жиль "ТАК - перестань быть злым"
источник
Хех, я редактировал свой ответ, чтобы включить это, как вы писали свой. Я думаю, я просто удалю свои правки. Я действительно хотел бы видеть, когда кто-то еще писал ответ.
Стивен Д
1
Строго говоря, ваш скрипт не усекает строки; скорее это оборачивает длинные строки, но не переупаковывает остаток.
Приостановлено до дальнейшего уведомления.
2

Вот функция Awk, которая разбивается на пробелы:

function wrap(text,   q, y, z) {
  while (text) {
    q = match(text, / |$/); y += q
    if (y > 72) {
      z = z RS; y = q - 1
    }
    else if (z) z = z FS
    z = z substr(text, 1, q - 1)
    text = substr(text, q + 1)
  }
  return z
}

Неожиданно это более производительным , чем сложить или FMT .

Источник

Стивен Пенни
источник
2

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

  1. Код не изменяет helloстроку с gsub()вызовами. С двумя аргументами gsub()действует на $0. Чтобы реально изменить halloпеременную, используйте gsub(..., ..., hallo).

  2. Вы получаете ноль в конце строки, потому что gsub()возвращает количество выполненных замен, и в какой-то момент вы добавляете это число к значению hallo.

Мне известны как минимум три утилиты, специально предназначенные для переноса и форматирования текстовых абзацев:

  1. fold, «фильтр для складывания линий», который является стандартной утилитой POSIX . Он просто вставляет новые строки и не переформатирует текст.

  2. fmt, «простой форматировщик текста», который также часто устанавливается по умолчанию в системах Unix и намного умнее, чем foldкогда дело доходит до перекомпоновки абзацев.

  3. par, « фильтр для переформатирования абзацев », который имеет дополнительные возможности для определения префиксов и суффиксов абзацев (таких как текст с рамкой ASCII вокруг него или комментарии в небольшом количестве исходного кода), и обрабатывает отступы и висячие отступы чуть лучше чем fmt.

Кусалананда
источник
0

Используя gensub, чтобы получить foldсемантику, вы можете запустить что-то вроде

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
JJoao
источник