使用哈希进行Perl替换

时间:2011-08-06 23:20:19

标签: regex perl

open (FH,"report");
read(FH,$text,-s "report");

$fill{"place"} = "Dhahran";
$fill{"wdesc:desc"} = "hot";
$fill{"dayno.days"} = 4;

$text =~ s/%(\w+)%/$fill{$1}/g;

print $text;

这是“报告”模板文件的内容

"I am giving a course this week in %place%. The weather is %wdesc:desc%
and we're now onto day no %dayno.days%. It's great group of blokes on the
course but the room is like the weather - %wdesc:desc% and it gets hard to
follow late in the day."

由于我不会进入的原因,我将使用的哈希中的一些键将包含点(。)或冒号(:),但正则表达式停止为这些工作,所以例如在上面的示例中,只有%place%被正确替换。顺便说一下,我的代码基于this example

对正则表达式的任何帮助都非常感激,或者可能有更好的方法......

3 个答案:

答案 0 :(得分:4)

你可以放松它并使用“任何不是%的任何序列”来替换可替换的令牌:

$text =~ s/%([^%]+)%/$fill{$1}/g;

答案 1 :(得分:3)

到目前为止的答案很好,但如果%foo%不是foo哈希中的关键字,您还应该决定使用%fill做什么。合理的选择是:

  • 将其替换为空字符串(这是当前解决方案所做的,因为在此上下文中undef被视为空字符串)
  • 不管它,"%foo%"保持原样。
  • 执行某种错误处理,可能在STDERR上打印警告,终止翻译或在文本中插入错误指示符。

其他一些与您的问题没有直接关系的观察结果:

  • 您应该使用open的三参数版本。
  • 这不是将整个文件读入字符串的最简洁方法。就此而言,对于你正在做的事情,你也可以一次处理一行输入。

以下是我可能会这样做的方法(此版本仅保留无法识别的"%foo%"字符串):

#!/usr/bin/perl

use strict;
use warnings;

my %fill = ( place        => 'Dhahran',
             'wdesc:desc' => 'hot',
             'dayno.days' => 4 );

my $filename = 'report';

open my $FH,,'<', $filename or die "$filename: $!\n";
while (my $line = <$FH>) {
    foreach my $key (keys %fill) {
        $line =~ s/\Q%$key%/$fill{$key}/g;
    }
    print $line;
}

如果存在无法识别的密钥,那么这个版本会因错误消息而死:

#!/usr/bin/perl

use strict;
use warnings;

my %fill = ( place        => 'Dhahran',
             'wdesc:desc' => 'hot',
             'dayno.days' => 4 );

my $filename = 'report';

open my $FH,,'<', $filename or die "$filename: $!\n";
while (my $line = <$FH>) {
    $line =~ s/%([^%]*)%/Replacement($1)/eg;
    print $line;
}

sub Replacement {
    my($key) = @_;
    if (exists $fill{$key}) {
        return $fill{$key};
    }
    else {
        die "Unrecognized key \"$key\" on line $.\n";
    }
}

答案 2 :(得分:1)

http://codepad.org/G0WEDNyH

$text =~ s/%([a-zA-Z0-9_\.\:]+)%/$fill{$1}/g;



默认情况下,\w等同于[a-zA-Z0-9_],因此您需要添加\.\: