昨天,我陷入了一个perl脚本。让我简化一下,假设有一个字符串(比如ABCDEABCDEABCDEPABCDEABCDEPABCDEABCD),首先我要在“E”出现的每个位置打破它,其次,在用户想要的位置打破它。但是,条件是,程序不应该在E跟随P的那些站点切割。例如,在这个序列中有6个Es,所以一个应该得到7个碎片,但是当2个Es跟随P时,一个将得到5个输出中的片段。
我需要有关第二种情况的帮助。假设用户不想在序列中的E的第5和第10个位置切断此序列,那么应该让程序只跳过这两个站点的相应脚本应该是什么?我的第一个案例的脚本是:
my $otext = 'ABCDEABCDEABCDEPABCDEABCDEPABCDEABCD';
$otext=~ s/([E])/$1=/g; #Main cut rule.
$otext=~ s/=P/P/g;
@output = split( /\=/, $otext);
print "@output";
请帮忙!
答案 0 :(得分:4)
要拆分“E”,除非它后面跟着“P”,你应该使用否定的前瞻断言。
来自perldoc perlre
“Look-Around Assertions”部分:
- (?图案)
零宽度负前瞻断言。
例如/foo(?!bar)/
匹配任何未出现“bar”的“foo”。
my $otext = 'ABCDEABCDEABCDEPABCDEABCDEPABCDEABCD';
# E E EP E EP E
my @output=split(/E(?!P)/, $otext);
use Data::Dumper; print Data::Dumper->Dump([\@output]);"
$VAR1 = [
'ABCD',
'ABCD',
'ABCDEPABCD',
'ABCDEPABCD',
'ABCD'
];
现在,为了不减少出现#2和#4,你可以做两件事:
编写一个非常奇特的正则表达式,在给定的出现时自动无法匹配。为了完整起见,我会把这个留给其他人尝试回答。
简单地将正确的碎片拼接在一起。
我太聪明了,没有想出一个很好的惯用方法,但是简单而肮脏的方式是:
my %no_cuts = map { ($_=>1) } (2,4); # Do not cut in positions 2,4
my @output_final;
for(my $i=0; $i < @output; $i++) {
if ($no_cuts{$i}) {
$output_final[-1] .= $output[$i];
} else {
push @output_final, $output[$i];
}
}
print Data::Dumper->Dump([\@output_final];
$VAR1 = [
'ABCD',
'ABCDABCDEPABCD',
'ABCDEPABCDABCD'
];
或者,更简单:
my %no_cuts = map { ($_=>1) } (2,4); # Do not cut in positions 2,4
for(my $i=0; $i < @output; $i++) {
$output[$i-1] .= $output[$i];
$output[$i]=undef; # Make the slot empty
}
my @output_final = grep {$_} @output; # Skip empty slots
print Data::Dumper->Dump([\@output_final];
$VAR1 = [
'ABCD',
'ABCDABCDEPABCD',
'ABCDEPABCDABCD'
];
答案 1 :(得分:0)
这是一个利用两个事实的肮脏技巧:
“小心”只是需要注意的一点。无论如何,我们的想法是在您不想要中断的位置替换空字节:
my $s = "ABCDEABCDEABCDEPABCDEABCDEPABCDEABCD";
my @nobreak = (4,9);
foreach (@nobreak) {
substr($s, $_, 1) = "\0";
}
"\0"
是一个表示空字节的转义序列,如"\t"
是一个标签。再说一遍:它不是角色0.我使用4和9因为那些位置有E。如果您现在打印字符串,它看起来像:
ABCDABCDABCDEPABCDEABCDEPABCDEABCD
因为空字节不显示,但是它们存在,我们将在稍后将它们交换出来。首先是分裂:
my @a = split(/E(?!P)/, $s);
然后将零字节交换回来:
$_ =~ s/\0/E/g foreach (@a);
如果您现在打印@a
,则会获得:
ABCDEABCDEABCDEPABCD
ABCDEPABCD
ABCD
这正是你想要的。请注意,split会删除分隔符(在本例中为E);如果你打算保留那些你可以在之后重新加上它们。如果分隔符来自更动态的正则表达式,则稍微复杂一点,请参见此处:
http://perlmeme.org/howtos/perlfunc/split_function.html
“示例9.保留分隔符”
如果@nobreak
位置有可能不是E,那么你必须在换掉它们时跟踪它们,以确保再次替换正确的角色。