정규식으로 정렬

정규식으로 정렬

POSIX 정규식 세트가 있습니다*

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

그리고 각 줄이 정규식 중 하나와 일치하는 파일은 다음과 같습니다.

BEGIN:VCARD
VERSION:3.0
N:Doe;Jane;;Ms;
URL:http://janedoe.com/
EMAIL:[email protected]
EMAIL:[email protected]
BDAY:1970-01-01
X-JABBER:[email protected]
X-ICQ:1234567890
END:VCARD

이 행을 기준으로 정렬하고 싶습니다.

  1. 정규식과 일치하는 줄 번호(FN으로 시작하는 줄이 N으로 시작하는 줄 앞에 오도록),
  2. 일치 그룹(X-ABC가 X-DEF 앞에 오도록)

이상적으로는 행의 다른 부분은 정렬되지 않아야 합니다. 따라서 EMAIL로 시작하는 행의 순서가 유지되어야 합니다. 따라서 예상되는 결과는 다음과 같습니다.

BEGIN:VCARD
VERSION:3.0
N:Doe;Jane;;Ms;
EMAIL:[email protected]
EMAIL:[email protected]
X-ICQ:1234567890
X-JABBER:[email protected]
BDAY:1970-01-01
URL:http://janedoe.com/
END:VCARD

이를 수행할 수 있는 기존 도구가 있습니까?

편집하다:구현 결과기반으로Lars Rohrbach의 답변.

* Gmail 연락처 내보내기 파일의 vCard 속성 순서입니다.

답변1

일반적인 sort명령은 포함할 특정 "사전"을 지정하는 방법을 제공하지 않으며, 명령을 사용하면 grep정규식 파일을 제공할 수 있지만 출력 순서는 변경되지 않습니다. 그러나 두 가지를 간단한 foreach루프에 넣을 수 있습니다. 다음은 bash 셸에서 실행되는 예입니다.

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

이는 정규식 파일의 각 정규식 행을 하나씩 가져와 입력 파일에서 일치하는 항목을 출력하므로 결과 출력은 정규식 순서로 정렬됩니다. 정확하게 일치하지 않는 입력 파일의 행은 출력에 표시되지 않습니다.

부록:요청에 따라 루프를 사용하는 버전은 다음과 같습니다 while.

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

답변2

정확히 이렇게 프레임을 구성한 것은 아니지만, 실제 목적을 고려하면 콜론 앞 부분을 잡아서 정렬하는 것이 더 간단할 것입니다. 다음은 별도의 정렬 키에서 별도의 배열 항목으로 행을 누적하고 끝에 도달하면 vcard를 플러시하는 Perl 스크립트입니다.

#!/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[^A-Z] ^FN[^A-Z] ^N[^A-Z] ... ^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} = ""; }
}

관련 정보