Найдите двойные кавычки (") в файле и скопируйте всю строку в другой файл. - PullRequest
0 голосов
/ 10 октября 2018

У меня есть требование, чтобы прочитать все файлы и искать(") и скопируйте всю строку в другой файл. Задача состоит в том, чтобы идентифицировать всю строку, когда в строке есть новый символ.

Формат файла такой: значения разделяются с помощьюразделитель |*| и заканчивается |##|.

В прикрепленном (изображении) выделенном зеленым цветом должен перейти в новый файл, логика будет проверяться на ", и если он находит строку чтения, начиная с(строка после | ## | до до следующего | ## |)

1

10338|*|BVL-O-G-01020-R4|*||*|BVL|*||*|Y|*|Y|*||*|CFC6E82284990A7AE040800AA5644B19|*|jmorlan|*|2011.12.21 15:52:01|##|
10358|*|BI-MED-CDMA-MCS-90-118-EXAM|*|Exam for 001-MCS-90-118:
Planning, Conducting and Reporting Post Marketing Surveillance "Studies and Safety Reporting from Non Trial Activities |*|GLOBAL_MEDICAL|*||*|Y|*|N|*||*|CFC6E822849A0A7AE040800AA5644B19|*|finke|*|2012.04.30 04:23:27|##|
10342|*|BVL-O-4-01020-R7|*||*|DVL|*||*|Y|*|Y|*||*|RRFC6E82284990A7AE040800AA5644B19|*|sppa|*|2011.12.21 15:52:01|##|

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Этот ответ предоставляет два решения - решение Gnu Awk и версию POSIX.

POSIX awk

awk '{r=r ? r "\n" $0 : $0}
     /\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile

GNU awk 1

awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile

GNU awk 2

awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile

На приведенных в вопросе данных примера все предоставленные решения дают следующий вывод:

10358|*|BI-MED-CDMA-MCS-90-118-EXAM|*|Exam for 001-MCS-90-118:
Planning, Conducting and Reporting Post Marketing Surveillance "Studies and Safety Reporting from Non Trial Activities |*|GLOBAL_MEDICAL|*||*|Y|*|N|*||*|CFC6E822849A0A7AE040800AA5644B19|*|finke|*|2012.04.30 04:23:27|##|

примечание: Возможно, у вас возникла проблема возврата каретки, если файл поступил с компьютера Windows.Пожалуйста, запустите файл dos2unix, прежде чем использовать его с этими инструментами.


Как это работает?(POSIX)

Используя POSIX-версию , мы можем сделать

awk '{r=r ? r "\n" $0 : $0}
      /\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile

Идея состоит в том, чтобы создать запись r с помощьюдобавление каждой строки к r.Если текущая строка заканчивается на "|##|", то мы проверяем, содержит ли запись r".Если это так, мы печатаем запись r и сбрасываем запись r в пустую строку.Если он не содержит, мы просто сбросили его.

Как это работает?(GNU)

Используя GNU , вы можете сделать это напрямую, используя разделитель записей RS

awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile

Идея в том, чтофайл содержит различные записи.В ОП четко указывалось, что информация записи разделена на поля, разделенные |*|, но, что более важно, сами записи разделены |##|.Таким образом, в представленном примере OP первая запись - это строка 1, а вторая запись - в строке 2 и в строке 3.

В вы можете определить разделитель записей с помощьюпеременной RS.В состоянии по умолчанию RS - это символ \n, который делает каждую строку отдельной записью, на которую может ссылаться $0.В POSIX разделителем записей может быть только один символ, который разделяет записи, в то время как в Gnu awk это может быть регулярное выражение (см. Добавление ниже).

Поскольку разделителем записей OP является строка"| ## |"после всех или без символа \n нам нужно определить RS=\\|##\\|\n?.Почему это так сложно?

  • символ | - это операция ИЛИ (оператор чередования) в регулярном выражении, поэтому мы должны ее избежать.Но поскольку строковые литералы, которые используются в качестве регулярных выражений, анализируются дважды, нам также необходимо избегать его дважды.Так что |\\| (см. здесь )

  • \n? потому, что кажется, что фактическим разделителем записей является строка "| ##| \ n ", но, возможно, некоторые записи не имеют символа новой строки, особенно последняя запись.

Когда вы печатаете записи, используя оператор print, он автоматически добавляет выходную записьразделитель ORS после каждой строки.По умолчанию это снова символ \n.Поскольку разделитель записей RS не является частью записи $0, необходимо обновить значение ORS до ORS="|##|\n".На этот раз не является регулярным выражением, поэтому вам вообще не нужно экранировать.

Оператор /"/ является сокращением для /"/{print $0}, что означает Если текущая запись $0 содержит", затем выведите текущую запись $0, за которой следует разделитель выходных записей ORS.

Примечание: , поскольку мы фактически уже используем Gnu awk, мы можем фактическиуменьшите все это еще больше до:

awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile

, который использует разделитель соответствующих записей RT, который соответствует тексту, найденному RS.Заменив оператор print на оператор printf, нам больше не нужно ORS и просто вручную добавьте RT к записи $0.


RS: Разделитель входных записей.Его значением по умолчанию является строка, содержащая один символ новой строки, что означает, что входная запись состоит из одной строки текста.Это также может быть пустая строка, в этом случае записи разделяются сериями пустых строк.Если это регулярное выражение, записи разделяются совпадениями регулярного выражения во входном тексте.

Способность RS быть регулярным выражением является расширением gawk.В большинстве других реализаций AWK, или если gawk находится в режиме совместимости (см. Опции), используется только первый символ значения RS.

ORS: Разделитель выходной записи.Он выводится в конце каждого оператора печати.Значением по умолчанию является "\ n", символ новой строки.

RT: (специфично для GNU AWK) Входной текст, который соответствует тексту, обозначенному RS, разделителем записей.Он устанавливается каждый раз при чтении записи.

источник: Руководство по GNU AWK

0 голосов
/ 10 октября 2018

Предполагая, что вы имеете в виду, что разделы между |##| должны рассматриваться как перевод строки, следующий вопрос: содержит ли вы в файле настоящие символы перевода строки?Если нет, то grep, вероятно, не будет очень эффективным, поскольку он работает построчно.Если предполагается, что какие-либо настоящие символы новой строки считаются частью текста, то, безусловно, grep будет недоволен.

Если вы действительно хотите сделать это за 1, введите grep:

grep-Eoz '(^ | \ | ## \ |) ([^ |] | \ | [^ #] | \ | # [^ #] | \ | ## [^ |]) "([^|] | \ | [^ #] | \ | # [^ #] | \ | ## [^ |]) (\ | ## \ || $) '

Это выглядитза любой последовательностью, которая начинается с | ## | (или является началом файла), следует несколько символов, кавычка и еще несколько символов, а затем заканчивается | ## | (или конец файла).z grep будет игнорировать любые символы новой строки в файле. Сложное выражение «любые символы» ([^|]|\|[^#]|\|#[^#]|\|##[^|])* состоит в том, что grep является жадным. Он в основном ищет повторяющиеся последовательности, которые не | ## |. Возможно, отключение жадности - это хорошо, но этозависит от мощности механизма регулярных выражений в вашей версии grep.

Но гораздо проще и, вероятно, быстрее, использовать sed, чтобы разбить записи и ввести "NULL" переводы строк:

sed 's / \ | ## \ | / \ x00 / g' | grep -z '"'

Это просто замена yнаш конец линии шаблона | ## |с нулевым символом, затем попросите grep найти кавычку, рассматривая нулевой символ как конец строки.

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