Постановка задачи:
Входной файл содержит текст с отступом в ноль или более символов табуляции. В частности, каждая строка на входе является одной из них:
- Пустой или
- Ноль или более вкладок (до предела; см. Ниже), за которыми следует символ, который не является ни пробелом, ни вкладкой (за которым следует ноль или более любого символа).
Там нет строк, которые
- Начните с нуля или более вкладок, а затем пробел. (Это означает, что нет строк, начинающихся с пробела.)
Или - Состоят полностью из одной или нескольких вкладок (и ничего больше).
или же - Начните с более чем определенного количества вкладок.
Входные данные должны быть логически разбиты на группы строк, которые все либо
- Пустой или
- Отступы с одинаковым количеством вкладок.
Пустые строки должны быть переданы на выход без изменений.
Должен быть указан список тегов; например, x
, y
, и zz
. Группа (непустых) строк, которые имеют нулевые табуляции (то есть не имеют отступов), заключаются в квадратные скобки <x>
и </x>
. Группа строк с отступом в одну вкладку должна заключаться в скобки <y>
и </y>
. Группа строк с двумя вкладками должна заключаться в скобки <zz>
и </zz>
. (Строки не будут иметь отступ с более чем двумя вкладками.)
Первая строка группы (непустой строки) должна иметь начальный тег, вставленный между вкладками и текстом. К последней строке группы должен быть добавлен конечный тег в конце текста. Группа может состоять из одной строки, поэтому первая строка также может быть последней строкой. Все строки группы, кроме первой, должны иметь дополнительный отступ (с пробелами, вставленными между вкладками и текстом) по ширине начального тега.
Например (используется ―→
для представления вкладки), этот ВХОД :
aaa ―→ Once upon a midnight dreary, ―→ while I pondered, weak and weary, Quoth the Raven, “Nevermore.” ―→ ―→ The quick brown fox ―→ ―→ jumps over the lazy dog. ―→ It was a dark and stormy night. ―→ Suddenly a shot rang out.
должны быть переведены в этот выход :
<x>aaa</x> ―→ <y>Once upon a midnight dreary, ―→ while I pondered, weak and weary,</y> <x>Quoth the Raven, “Nevermore.”</x> ―→ ―→ <zz>The quick brown fox ―→ ―→ jumps over the lazy dog.</zz> ―→ <y>It was a dark and stormy night. ―→ Suddenly a shot rang out.</y>
Решение:
Очевидно, что мы не совсем знаем, что делать со строкой ввода, пока не прочитаем следующую строку. Эта проблема обычно решается путем сохранения содержимого одной строки для обработки после прочтения следующей.
Итак, вот оно:
awk ' BEGIN { num_tags = split("x y zz", tags) for (i=1; i<=num_tags; i++) { len = length(tags[i]) + 2 tag_pad[i] = "" for (j=1; j<=len; j++) tag_pad[i] = tag_pad[i] " " } } { if (NF == 0) indent_num = 0 else { indent_num = index($0, $1) indent_str = substr($0, 1, indent_num-1) restOfLine = substr($0, indent_num) } if (indent_num != saved_indent_num && saved != "") { print saved "</" tags[saved_indent_num] ">" saved = "" } if (NF == 0) print else if (indent_num > num_tags) { errmsg = "Error: line %d has an indent level of %d.\n" printf errmsg, NR, indent_num > "/dev/stderr" exit 1 } else if (indent_num == saved_indent_num) { print saved saved = indent_str tag_pad[indent_num] restOfLine } else saved = indent_str "<" tags[indent_num] ">" restOfLine saved_indent_num = indent_num } END { if (saved != "") print saved "</" tags[saved_indent_num] ">" } '
НАЧАТЬ блок инициализирует тэги ( x
, y
и zz
) путем разделения разделенных пробелами строку. tag_pad
Массив содержит достаточное количество пробелов, чтобы соответствовать ширине тегов ( в том числе <
и >
): tag_pad[1]
и tag_pad[2]
три пространства; tag_pad[3]
это четыре пробела.
Прочитав строку ввода, мы ее анализируем. Если в нем нет полей ( NF == 0
), оно должно быть пустым (поскольку мы указали, что ни одна строка не состоит целиком из пробелов и табуляций), поэтому установите indent_num
значение 0. В противном случае измерьте отступ, найдя местоположение $1
(первое слово) в $0
( вся линия). index
возвращает значение, начинающееся с 1, так что на самом деле это на единицу больше, чем количество пробельных символов перед первым непробельным символом (и, помните, мы предполагаем, что это все вкладки). Это повезло, потому что теперь indent_num
соответствует записям в tags
и tag_pad
массивах. Затем мы разделяем строку на indent_str
(пробел) и restOfLine
(все после отступа).
Теперь мы полагаемся на сохраненную информацию. Если эта строка имеет отступ, отличный от предыдущего, мы начинаем новую группу. Если есть сохраненная линия, записать его, с соответствующим закрывающим тегом в конце строки.
Если текущая строка пуста, просто распечатайте ее. Проверьте, не является ли текущий уровень отступа слишком высоким, и выведите его, если это так. Если текущий отступ такой же, как и предыдущий, это продолжение строки уже запущенной группы, поэтому просто напечатайте сохраненную (предыдущую) строку и создайте новую saved
строку, которая является текущей строкой с шириной текущей тег вставлен между отступом и текстом. В противном случае мы начинаем новую группу, поэтому создайте saved
строку, которая является текущей строкой, с начальным тегом (самим), вставленным между отступом и текстом.
Когда мы доберемся до конца ввода, закончим текущую группу, как мы делали раньше.