我想根据正则表达式的结果对文件进行排序。例如,如果我在 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 解决方案无济于事。
另外,我想使用正则表达式执行此操作的原因是这样我可以扩展我的排序算法以在其他情况下工作。用它来对方法声明、导入语句等进行排序。
答案1
按行内容的任意函数排序的通用方法如下:
- 获取要排序的键,并将其复制到行首
- 种类
- 删除行首的键
在这种特殊情况下,您可以使用以下关键:该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);
}
}