정규식 결과를 기준으로 입력 파일 정렬

정규식 결과를 기준으로 입력 파일 정렬

정규식 결과에 따라 파일을 정렬하고 싶습니다. 예를 들어 Obj-C에 다음과 같은 속성 선언이 있는 경우

@property (nonatomic, strong) id <AlbumArtDelegate, UITextFieldDelegate> *albumArtView; // 1
@property (nonatomic, strong, readonly) UIImageView *profileView;  // 2
@property (nonatomic, strong, readwrite) UIButton *postFB;          // 3
@property (nonatomic, assign) UIButton *saveButton;      // 4

기본적으로는 [4, 1, 2, 3]순으로 정렬되는데, 실제 속성 이름인 [1, 3, 2, 4]순으로 정렬하고 싶습니다. 속성 이름만 알아내는 정규식을 작성할 수 있고 해당 표현식의 결과를 기준으로 정렬할 수 있나요?

이 작업을 수행할 수 있는 내장된 Unix 도구가 있습니까? 저는 Xcode에서 작업 중이므로 VIM/emacs 솔루션이 도움이 되지 않습니다.

또한 정규식을 사용하여 이 작업을 수행하려는 이유는 다른 상황에서도 작동하도록 정렬 알고리즘을 확장할 수 있기 때문입니다. 메소드 선언, import 문 등을 정렬하는 데 사용합니다.

답변1

행 내용의 기능을 기준으로 정렬하는 일반적인 방법은 다음과 같습니다.

  1. 정렬할 키를 가져와 행의 시작 부분에 복사합니다.
  2. 유형
  3. 줄 시작 부분의 키 삭제

이 특별한 경우에는 다음 키를 사용할 수 있습니다. 프로그램은 sed마지막 식별자부터 끝까지 줄을 출력합니다.

% sed -e 's/^.*[^[:alnum:]_]\([[:alpha:]][[:alnum:]_]*\)/\1/' < decls

albumArtView; // 1
profileView;  // 2
postFB;          // 3
saveButton;      // 4

이러한 키를 원래 행과 나란히 배치하려면 다음을 수행하세요.

% paste <(sed -e 's/^.*[^[:alnum:]_]\([[:alpha:]][[:alnum:]_]*\)/\1/' < decls) decls

정렬하세요...

| sort

두 번째 필드(원래 행)만 유지합니다.

| cut -f 2-

모두 정리하면(표시할 내용이 있도록 역순으로 정렬):

% paste <(sed -e 's/^.*[^[:alnum:]_]\([[:alpha:]][[:alnum:]_]*\)/\1/' < decls) decls \
  | sort -r \
  | cut -f 2-

@property (nonatomic, assign) UIButton *saveButton;      // 4
@property (nonatomic, strong, readonly) UIImageView *profileView;  // 2
@property (nonatomic, strong, readwrite) UIButton *postFB;          // 3
@property (nonatomic, strong) id <AlbumArtDelegate, UITextFieldDelegate> *albumArtView; // 1

답변2

PIPED-DATA | sed -r "s/(\*\w+)/\x01&\x01/" | sort -k2 -t$'\x01' |tr -d $'\x01'

귀하의 경우에는 위의 스크립트로 충분합니다. 실제로 기본적으로 단일 키 필드 정렬에는 충분합니다. 동일한 스크립트의 경우 확장하고 계속 읽으세요.


다음 스크립트는 정렬할 필드를 설정합니다.2, 그러나 장소 레이아웃은 매우 유연합니다. 필요한 경우 적절한 정규식 패턴을 지정하고 그에 따라 정렬 옵션을 변경하여 여러 필드를 정렬할 수 있습니다.

(각 필드 패턴은 일반 대괄호 와 로 )묶어야 합니다 'single-quoted'.

귀하가 제공하는 패턴은 귀하가 선택한 고유 문자로 정의됩니다. sed고유한 구분 기호도 필요합니다. 스크립트는 구분 기호 \x01\x02. 이러한 구분 기호 값은 일반적으로 텍스트 파일에 표시되지 않기 때문에 선택되었습니다.

필드 구분 기호가 아닌 필드 조합을 기준으로 설정을 고려해야 합니다.

n=2                                  # field number to sort on
p=( '(.*)'  '(\*\w+)'  '(.*)' )      # Set up regex field patterns

f=; r=; d=$'\x01';  x=$'\x02'        # Build patterns and delimiters
for (( i=0; i<${#p[@]}; i++ )) ;do 
   f+="${p[i]}"; r+="\\$((i+1))$x"
done

sed -r "s$d$f$d$r$d" file |sort -k$n -t"$x" |tr -d  "$x"

산출:

@property (nonatomic, strong) id <AlbumArtDelegate, UITextFieldDelegate> *albumArtView; // 1
@property (nonatomic, strong, readwrite) UIButton *postFB;          // 3
@property (nonatomic, strong, readonly) UIImageView *profileView;  // 2
@property (nonatomic, assign) UIButton *saveButton;      // 4

답변3

sort -k 5 ~/Temp/data

Cygwin에서 저에게 효과적입니다.

답변4

나는 첫 번째 캡처를 기준으로 파일을 정렬하기 위해 정규식을 입력할 수 있는 Perl 스크립트를 만들었습니다. 그런 다음 문자열 또는 숫자 비교를 수행하도록 플래그를 설정할 수 있습니다. 이 코드 예제를 .pl 파일에 넣으면 됩니다.

매우 간단합니다. 논리는 20-37행에 있습니다.

#! /usr/bin/perl
# Created by pete Nixon

use Getopt::Long;
use strict;
use Cwd qw(abs_path);

my $exec_path = abs_path($0);
   $exec_path =~ s/(.*\x2f)[^\x2f]+$/$1/g;
my $path = abs_path($1);

&getCommandLineArguments;

my $file_flag;
my $regex;
my $type_flag;
my @lines;
my @sortedLines;

open (FILE, $file_flag) || die "Couldn't open rule file, $!";
while (<FILE>) {
    chomp $_;
    if ($_ =~ /^\s*\n/) {
        next;
    }
    push (@lines, $_);
}

if ($type_flag eq 1) {
    @sortedLines = sort { ($a =~ m/$regex/)[0] <=> ($b =~ m/$regex/)[0]} @lines; # where the magic happens
} else {
    @sortedLines = sort { ($a =~ m/$regex/)[0] cmp ($b =~ m/$regex/)[0]} @lines; # where the magic happens
}

foreach (@sortedLines) {
    print "$_\n";
}

sub getCommandLineArguments() {
    my $help;
    my $clear = "[0m";
    my $black = "[0;30m";
    my $blue = "[0;34m";
    my $green = "[0;32m";
    my $cyan = "[0;36m";
    my $red = "[0;31m";
    my $purple = "[0;35m";
    my $brown = "[0;33m";
    my $gray = "[0;37m";
    my $darkGray = "[1;30m";
    my $lightBlue = "[1;34m";
    my $lightGreen = "[1;32m";
    my $lightCyan = "[1;36m";
    my $lightRed = "[1;31m";
    my $lightPurple = "[1;35m";
    my $yellow = "[1;33m";
    my $white = "[1;37m";
    GetOptions (
        'file|f=s' =>   \$file_flag,
        'regex|r=s' => \$regex,
        'type|t=s' => \$type_flag,
        'help|h|?' => \$help
        ) or die ("Error in command line arguments$clear\n");
    if ($help || $file_flag eq undef && $regex eq undef) {
        print "$green================================================================================$clear\n";
        print "$red WHAT DOES THIS SCRIPT DO?\n$clear";
        print "$cyan    - This program a regex and sorts a line based on it.\n$clear";
        print "$red HOW DO I USE THIS SCRIPT?\n$clear";
        print "$cyan    - Type the name of this script, space, options (see the next section)\n$clear";
        print "$green   SAMPLE: '$clear" . "sortbyregex.pl -f file -r \"regex\" -t (1|2)$green'\n$clear";
        print "$red WHAT OPTIONS ARE AVAILABLE?\n$clear";
        print "$yellow  -f, --file\n$clear";
        print "$cyan    - Use to specify a regex\n$clear";
        print "$yellow  -r, --regex\n$clear";
        print "$cyan    - Use to specify the regex used for sorting, must include one capture\n$clear";
        print "$yellow  -t, --type\n$clear";
        print "$cyan    - Use to specify the type of sorting 1 = numeric 2 = string\n$clear";
        print "$yellow  -h, --help, -?\n$clear";
        print "$cyan    - Use to see this help... so... yeah...\n$clear";
        print "$green================================================================================$clear\n";
        exit(0);
    }
}

관련 정보