-1

Я хочу пометить текстовое содержимое (с помощью XML-подобных тегов) на основе глубины отступа. Пустые строки должны быть сохранены. Содержание приведенного ниже примера имеет отступ с 1, 2 или 3 вкладками.

ВХОД

aaa
  bbb
  bbb

aaa

      ccc
      ccc
  bbb
  bbb

Я хочу сгруппировать строки на одном уровне отступов и преобразовать эти уровни отступов в теги x , y и z , например так:

ВЫХОД

<x>aaa</x>
     <y>bbb
        bbb</y>

 <x>aaa</x>

        <z>ccc
           ccc</z>
    <y>bbb
       bbb</y>

Как я могу это сделать?

1 ответ1

0

Постановка задачи:

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

  • Пустой или
  • Ноль или более вкладок (до предела; см. Ниже), за которыми следует символ, который не является ни пробелом, ни вкладкой (за которым следует ноль или более любого символа).

Там нет строк, которые

  • Начните с нуля или более вкладок, а затем пробел.  (Это означает, что нет строк, начинающихся с пробела.)
    или же
  • Состоят полностью из одной или нескольких вкладок (и ничего больше).
    или же
  • Начните с более чем определенного количества вкладок.

Входные данные должны быть логически разбиты на группы строк, которые все либо

  • Пустой или
  • Отступы с одинаковым количеством вкладок.

Пустые строки должны быть переданы на выход без изменений.

Должен быть указан список тегов; например, 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] ">"
    }
    '

Блок BEGIN инициализирует теги (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 строку, которая является текущей строкой, с начальным тегом (самим), вставленным между отступом и текстом.

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .