Сортировка по регулярным выражениям

У меня есть набор регулярных выражений POSIX *

^BEGIN:VCARD\r$ ^VERSION[^AZ] ^FN[^AZ] ^N[^AZ] ^NICKNAME[^AZ] ^EMAIL[^AZ] ^X-\([AZ-]*\) ^TEL[^AZ] ^ADR[^AZ] ^ORG[^AZ] ^TITLE[^AZ] ^BDAY[^AZ] ^URL[^AZ] ^ROLE[^AZ] ^NOTE[^AZ] ^END:VCARD\r$ 

и файл с строками, каждый из которых соответствует одному из регулярных выражений:

 BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; URL:http://janedoe.com/ EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com BDAY:1970-01-01 X-JABBER:jane.doe@example.org X-ICQ:1234567890 END:VCARD - BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; URL:http://janedoe.com/ EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com BDAY:1970-01-01 X-JABBER:jane.doe@example.org X-ICQ:1234567890 END:VCARD - BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; URL:http://janedoe.com/ EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com BDAY:1970-01-01 X-JABBER:jane.doe@example.org X-ICQ:1234567890 END:VCARD 

Я бы хотел сортировать эти строки в соответствии с

  1. номер строки совпадения регулярных выражений (так что строки, начинающиеся с FN, поступают до строк, начинающихся с N),
  2. (так, чтобы X-ABC появился до X-DEF)

В идеале, другие части линий не должны сортироваться (поэтому последовательность строк, начинающихся с EMAIL, должна быть оставлена ​​в покое). Ожидаемый результат должен быть следующим:

 BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com X-ICQ:1234567890 X-JABBER:jane.doe@example.org BDAY:1970-01-01 URL:http://janedoe.com/ END:VCARD - BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com X-ICQ:1234567890 X-JABBER:jane.doe@example.org BDAY:1970-01-01 URL:http://janedoe.com/ END:VCARD - BEGIN:VCARD VERSION:3.0 N:Doe;Jane;;Ms; EMAIL:jdoe@example.org EMAIL:jane.doe@janedoe.com X-ICQ:1234567890 X-JABBER:jane.doe@example.org BDAY:1970-01-01 URL:http://janedoe.com/ END:VCARD 

Существует ли для этого инструмент?

Изменить: Результирующая реализация основана на ответе Ларса Рорбаха .

* Это последовательность свойств vCard в файле экспорта контактов Gmail.

  • Пакетная сортировка нескольких файлов и удаление повторяющихся строк из нескольких файлов - на месте, если возможно
  • Сортировка и резервное копирование файлов log4j
  • Сортировка unix в алфавитном порядке, а затем в численном выражении, не работающая по назначению
  • Сортировка файлов в каталогах, названных префиксом файла
  • Сортировка списков, когда нет начальных нулей
  • Сортировка чисел и соответствующих единиц в столбцах
  • Как сортировать данные в файле с помощью скрипта?
  • Сортировка выровненных столбцов
  • 2 Solutions collect form web for “Сортировка по регулярным выражениям”

    Обычная команда sort не предоставляет включенного способа указать ваш конкретный «словарь», и, хотя команда grep позволяет вам предоставить файл регулярных выражений, он не изменит порядок вывода. Но вы можете объединить оба в простой цикл foreach – вот пример, который работает в оболочке bash:

     for i in `cat fileofregexp`; do grep "$i" myinputfile; done 

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

    Приложение: в соответствии с запросом, вот версия с использованием цикла while:

     while IFS= read -ri; do grep "$i" myinputfile; done < fileofregexp 

    Это не совсем то, как вы создавали его, но, учитывая вашу фактическую цель, было бы проще захватить часть перед двоеточием и отсортировать ее. Вот сценарий Perl, который накапливает строки из отдельных ключей сортировки в отдельных записях массива и сбрасывает vcard, когда он достигает конца.

     #!/usr/bin/perl -n BEGIN { @headers = qw(BEGIN VERSION FN N NICKNAME EMAIL X- TEL ADR ORG TITLE BDAY URL ROLE NOTE END); for $h (@headers) { $data{$h} = ""; } } if (/^([^:]+):/) { $data{exists $data{$1} ? $1 : "X-"} .= $_; if ($1 eq 'END') { for $h (@headers) { print $data{$h}; $data{$h} = ""; } } } else { print; } 

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

     #!/usr/bin/perl -n BEGIN { @regexps = qw(^BEGIN:VCARD\r$ ^VERSION[^AZ] ^FN[^AZ] ^N[^AZ] ... ^END:VCARD\r$); for $r (@regexps) { $data{$r} = ""; } } for $r (@regexps) { next unless $_ =~ $r; $data{$r} .= $_; last; } if ($_ =~ $regexps[@regexps-1]) { for $r (@regexps) { print "++", $data{$r}; $data{$r} = ""; } } 
    Interesting Posts

    Почему я не могу передать файл через wget (FTP) с помощью функции exec () в PHP?

    Как эффективно искать список строк в большой директории кода

    Что может привести к чрезмерному замедлению кэширования кэша в большом кластере?

    Как установить subversion 1.6.x на SLE11?

    Правило Udev автоматически отключает сенсорную панель при подключении USB-мыши

    Подсчитайте количество строк из предыдущей программы

    Вставка переменной Bash – Perl Script

    Как построить кросс-компилятор AVR под Gentoo Linux?

    проблема с неактивным RAID 5

    Как отключить заставку и управление питанием в Linux по командной строке?

    получать сигнал до того, как процесс будет убит убийцей / группами OOM

    Клонирование вывода терминала

    Выполнение chown в скрипте bash вызывает ошибки

    Как установить пароль нового пользователя после того, как учетная запись уже создана?

    Что такое rpc.statd, какие порты следует прослушивать и как его убить?

    Linux и Unix - лучшая ОС в мире.