所以我的Perl脚本基本上是一个字符串,然后通过多次搜索并替换它来尝试清理它,如下所示:
$text =~ s/<[^>]+>/ /g;
$text =~ s/\s+/ /g;
$text =~ s/[\(\{\[]\d+[\(\{\[]/ /g;
$text =~ s/\s+[<>]+\s+/\. /g;
$text =~ s/\s+/ /g;
$text =~ s/\.*\s*[\*|\#]+\s*([A-Z\"])/\. $1/g; # replace . **** Begin or . #### Begin or ) *The
$text =~ s/\.\s*\([^\)]*\) ([A-Z])/\. $1/g; # . (blah blah) S... => . S...
正如你所看到的,我正在处理令人讨厌的HTML并且必须将其击败。
我希望有一种更简单,美观的方式来做到这一点。我有大约50行,看起来就像上面那样。
我通过使用哈希来解决了这个问题的一个版本,其中键是注释,哈希是reg表达式,如下所示:
%rxcheck = (
'time of day'=>'\d+:\d+',
'starts with capital letters then a capital word'=>'^([A-Z]+\s)+[A-Z][a-z]',
'ends with a single capital letter'=>'\b[A-Z]\.'
}
这就是我使用它的方式:
foreach my $key (keys %rxcheck) {
if($snippet =~ /$rxcheck{ $key }/g){ blah blah }
}
当我尝试使用哈希表示密钥是表达式时,问题就出现了,它指向我要用它替换它的东西......并且它有1美元或2美元。
%rxcheck2 = (
'(\w) \"'=>'$1\"'
}
以上是这样做的:
$snippet =~ s/(\w) \"/$1\"/g;
但我似乎无法将“$ 1”部分传递到正则表达式字面上(我认为这是正确的单词......即使我使用'标记,似乎正在解释$ 1。)因此,这导致:
if($snippet =~ /$key/$rxcheck2{ $key }/g){ }
这不起作用。
所以有2个问题:
简单:如何以一种易于编辑的方式处理大量的正则表达式,这样我就可以更改和添加它们而不必仅仅剪切和粘贴线条?
更难:我如何使用哈希(或数组,如果我有,我想要包括多个部分,如1)部分搜索,2)替换3)评论,4)全局/不区分大小写修饰符),如果这实际上是最简单的方法吗?
感谢您的帮助 -
答案 0 :(得分:10)
由于单个正则表达式似乎没有多少共享结构,所以实际上并没有比仅仅列出命令更简单或更清晰的方式。减少代码重复的一种常见方法是将$text
移到$_
,这样就不必说:
$text =~ s/foo/bar/g;
你可以说:
s/foo/bar/g;
这样做的一个常见习惯是使用简并for()
循环作为局部化器:
for($text)
{
s/foo/bar/g;
s/qux/meh/g;
...
}
此块的范围将保留$_
的任何预先存在的值,因此无需明确local
ize $_
。
此时,你已经消除了几乎所有非样板人物 - 即使在理论上它也能缩短多少?
除非你真正想要的(正如你的问题#2所暗示的)改进了模块性,例如,能够迭代,报告,计算所有正则表达式。
您可以使用qr//
语法引用替换的“搜索”部分:
my $search = qr/(<[^>]+>)/;
$str =~ s/$search/foo,$1,bar/;
但是,我不知道如何充分引用“替换”部分。我曾希望qr//
也适用于此,但事实并非如此。有两种选择值得考虑:
<强> 1。在eval()
循环中使用foreach
。这可以让您保留当前的%rxcheck2
哈希值。缺点:你应该始终关注字符串eval()
的安全性。
<强> 2。使用一组匿名子程序:
my @replacements = (
sub { $_[0] =~ s/<[^>]+>/ /g; },
sub { $_[0] =~ s/\s+/ /g; },
sub { $_[0] =~ s/[\(\{\[]\d+[\(\{\[]/ /g; },
sub { $_[0] =~ s/\s+[<>]+\s+/\. /g },
sub { $_[0] =~ s/\s+/ /g; },
sub { $_[0] =~ s/\.*\s*[\*|\#]+\s*([A-Z\"])/\. $1/g; },
sub { $_[0] =~ s/\.\s*\([^\)]*\) ([A-Z])/\. $1/g; }
);
# Assume your data is in $_
foreach my $repl (@replacements) {
&{$repl}($_);
}
当然,你可以使用哈希代替一些更有用的密钥作为哈希,和/或你可以使用包含注释或其他信息的多值元素(或哈希值)。
答案 1 :(得分:4)
哈希不好,因为它们是无序的。我找到一个数组数组,其第二个数组包含一个编译的正则表达式和一个字符串到eval(实际上它是一个双eval)效果最好:
#!/usr/bin/perl
use strict;
use warnings;
my @replace = (
[ qr/(bar)/ => '"<$1>"' ],
[ qr/foo/ => '"bar"' ],
);
my $s = "foo bar baz foo bar baz";
for my $replace (@replace) {
$s =~ s/$replace->[0]/$replace->[1]/gee;
}
print "$s\n";
我认为j_random_hacker的第二个解决方案远远优于我的。单个子程序为您提供最大的灵活性,比我的/ee
解决方案快一个数量级:
bar <bar> baz bar <bar> baz
bar <bar> baz bar <bar> baz
Rate refs subs
refs 10288/s -- -91%
subs 111348/s 982% --
以下是产生这些数字的代码:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark;
my @subs = (
sub { $_[0] =~ s/(bar)/<$1>/g },
sub { $_[0] =~ s/foo/bar/g },
);
my @refs = (
[ qr/(bar)/ => '"<$1>"' ],
[ qr/foo/ => '"bar"' ],
);
my %subs = (
subs => sub {
my $s = "foo bar baz foo bar baz";
for my $sub (@subs) {
$sub->($s);
}
return $s;
},
refs => sub {
my $s = "foo bar baz foo bar baz";
for my $ref (@refs) {
$s =~ s/$ref->[0]/$ref->[1]/gee;
}
return $s;
}
);
for my $sub (keys %subs) {
print $subs{$sub}(), "\n";
}
Benchmark::cmpthese -1, \%subs;
答案 2 :(得分:4)
你说你正在处理HTML。你现在意识到,与短暂而脆弱的解决方案相比,这几乎是一场失败的战斗。
正确的HTML解析器可以让您的生活更轻松。 HTML::Parser可能很难使用,但CPAN上还有其他非常有用的库,如果你可以指定你正在尝试做什么而不是如何