正規表現の結果に基づいて入力ファイルをソートする

正規表現の結果に基づいて入力ファイルをソートする

正規表現の結果に基づいてファイルをソートしたいと思います。たとえば、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

2番目のフィールド(元の行)のみを保持します。

| 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);
    }
}

関連情報