Используя awk, как перепечатать найденный шаблон с символом новой строки? - PullRequest
2 голосов
/ 29 марта 2012

У меня есть текстовый файл в формате:

aaa: bcd;bcd;bcddd;aaa:bcd;bcd;bcd; 

Где "bcd" может быть любой длины любых символов, кроме ; или :

Я хочу напечатать текстовый файл в формате:

aaa: bcd;bcd;bcddd;
aaa: bcd;bcd;bcd;

-etc-

Мой метод решения этой проблемы состоял в том, чтобы выделить шаблон ";...:" и затем перепечатать этот шаблон без начального ;

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

Возможно ли это? Если нет, не могли бы вы, пожалуйста, направить меня таким образом?

Ответы [ 4 ]

1 голос
/ 29 марта 2012

Это может сработать для вас:

 awk '{gsub(/[^;:]*:/,"\n&");sub(/^\n/,"");gsub(/: */,": ")}1' file
  1. Добавить новую строку (\n) перед любой строкой, не содержащей ; или :, за которой следует :
  2. Удалите все символы новой строки, добавленные перед началом строки.
  3. Замените все :, за которыми не должно быть ни много пробелов, на :, за которым следует один пробел.
  4. Печатьвсе строки.

Или это:

 sed 's/;\([^;:]*: *\)/;\n\1 /g' file
1 голос
/ 29 марта 2012

Мы не можем быть полностью уверены в вариабельности частей aaa или bcd;предположительно, каждый из них может быть почти чем угодно.

Вам, вероятно, следует искать:

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

Это составляет единицу, которую вы хотите сопоставить.

/[^:;]+:([^:;]+;)+/

Таким образом, вы можете заменить то, что было найдено, тем же, после которого следует новая строка, а затем распечатать результат.Единственный трюк - избегать лишних переводов строки.

Пример сценария:

{
echo "aaa: bcd;bcd;bcddd;aaa:bcd;bcd;bcd;" 
echo "aaz: xcd;ycd;bczdd;baa:bed;bid;bud;"
} |
awk '{ gsub(/[^:;]+:([^:;]+;)+/, "&\n"); sub(/\n+$/, ""); print }'

Пример вывода

aaa: bcd;bcd;bcddd;
aaa:bcd;bcd;bcd;
aaz: xcd;ycd;bczdd;
baa:bed;bid;bud;

Перефразируя вопрос в комментарии:

Почему регулярное выражение не включает символы перед двоеточием (что именно оно и должно делать, но я не понимаю, почему)?Я не понимаю, что «нарушает» или заканчивает регулярное выражение.

Как я пытался объяснить в верхней части, вы ищете то, что мы можем назвать «словами», то есть последовательностями символов, которыене являются ни двоеточием, ни точкой с запятой.В регулярном выражении это [^:;]+, что означает один или несколько (+) класса отрицанных символов - один или несколько символов, не являющихся двоеточиями, не запятыми.

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

    / [^:;]+ : ( [^:;]+ ; ) + /

Косые черты, конечно, просто обозначают концы.Первый кластер - это слово;тогда есть двоеточие.Затем в скобках указана группа, помеченная + в конце.Это означает, что содержимое группы должно встречаться как минимум один раз и может происходить в любое количество раз больше, чем это.Что внутри группы?Ну, слово, за которым следует точка с запятой.Это не должно быть одно и то же слово каждый раз, но там должно быть слово.Если что-то может происходить ноль или более раз, то вместо + вы, конечно, используете *.

Ключом к остановке регулярного выражения является то, что aaa: в серединепервая строка не состоит из слова, за которым следует точка с запятой;за этим словом следует двоеточие.Таким образом, регулярное выражение должно быть остановлено до этого, потому что aaa: не соответствует группе.Поэтому gsub() находит первую последовательность и заменяет этот текст тем же материалом и новой строкой (это, конечно, "&\n").Затем он (gsub()) возобновляет поиск сразу после окончания заменяемого материала, и - о чудо - за словом следует двоеточие, а за некоторыми словами следуют точки с запятой, поэтому есть второе совпадение, которое следует заменить на егооригинальный материал плюс перевод строки.

Я думаю, что $0 должен содержать перевод строки в конце строки.Следовательно, без sub() для удаления завершающих строк новой строки print (подразумевается $0 с новой строкой) сгенерировало пустую строку, которую я не хотел выводить, поэтому я удалил посторонние символы новой строки.Символ новой строки в конце $0 не будет совпадать с gsub(), поскольку за ним не следует двоеточие или точка с запятой.

0 голосов
/ 29 марта 2012

Обычные awk gsub () и sub () не позволяют указывать компоненты в строках замены. Gnu awk - "gawk" - предоставляет "gensub ()", который разрешает "gensub (/ (;) (. +) :) /, "\ 1 \ п \ 2", "г") "

0 голосов
/ 29 марта 2012

Не знаю, как это сделать в awk, но с sed это делает то, что, я думаю, вам нужно:

$ nl='
'
$ sed "s/\([^;]*:\)/\\${nl}\1/g" input

Первая команда устанавливает переменную оболочки $ nl в строку, содержащую одну новую строку.Некоторые версии sed позволяют использовать \ n внутри строки замены, но не все это допускают.Это сохраняет любые пробелы, которые появляются после финала;и помещает его в начало строки.Чтобы избавиться от этого, вы можете сделать

$ sed "s/\([^;]*:\)/\\${nl}\1/g; s/\n */\\$nl/g" input
...