Как я могу пометить текст на основе отступа?

327
Ramaprakasha

Я хочу пометить текстовое содержимое (с помощью 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
Если вы хотите, чтобы были добавлены пустые строки (как вы показали), вы должны сказать об этом. И ваш пример противоречив - сравните две строфы. Scott 7 лет назад 0
Я отредактировал вопрос на основе вашего мнения. Ramaprakasha 7 лет назад 0
Спасибо за исправление несоответствия отступов тегов и данных, но вы пропустили мою мысль о пустых строках. Ваш входной набор данных имеет десять строк: строка 1 - «111», строки 2 и 3 - «222», строка 4 - пустая и т. Д. Ваш вывод имеет длину в двенадцать строк, не только сохраняя ранее существующие пустые строки, но и добавляя один в 1½ (между «222» и «111») и другой в 8½ (между «333» и «222»). Вы хотите, чтобы это произошло? (Или это опечатка в вашем вопросе?) Scott 7 лет назад 0
Ой, извини. Да, это была опечатка. Я исправил это сейчас. Ramaprakasha 7 лет назад 0
Так как я хотел пометить текст, я изменил цифры на `a`,` b`, `c`. Ramaprakasha 7 лет назад 0
Таким образом, вы хотите удалить все символы `<>` и все символы между ними, сохраняя при этом переводы строки и возврат каретки, а также все другие символы и позиции строк за вычетом удаленных символов, затрагивающих только позиции строк ... это помогает уточнить, о чем вы спрашивали Я думаю. Вероятно, простое регулярное выражение с sed или grep или что-то, возможно, для хорошей отправной точки. Pimp Juice IT 7 лет назад 0
Нет, это противоположно этому. Теперь я уточнил, добавив заголовки ввода и вывода. Ramaprakasha 7 лет назад 0
Вы могли бы написать сценарий, но он будет довольно сложным. Вам нужно помнить, какой последний тег вы открыли, и читать файл построчно. Seth 7 лет назад 0
Вы видели мой ответ на ваш вопрос? Работает ли это для вас? (См. [Что я должен делать, когда кто-то отвечает на мой вопрос?] (// superuser.com/help/someone-answers)) Scott 7 лет назад 0
Извините, у меня произошел сбой, и мне пришлось заново установить мою ОС, поэтому я не смог ответить вам. Я принял ваш ответ. Работает отлично Ramaprakasha 7 лет назад 0

1 ответ на вопрос

0
Scott

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

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

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

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

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

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

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

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

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

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

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