用哈希值替换数组元素

时间:2011-10-24 23:01:49

标签: perl date hash map

我正在尝试编写一个Perl脚本,该脚本将在2011年10月24日的Pattern中使用日期并将其转换为10,24,2011。

为了做到这一点,我准备了一个哈希,它将月份名称作为键,数值代表月份的位置作为值。

我将读取输入字符串,使用正则表达式从上面的格式中提取月份名称。

将此月份名称替换为与月份对应的值作为键。

这是我到目前为止编写的脚本,但它对我不起作用。

@dates数组将包含此格式的所有元素 - > 2011年10月24日。

%days=("January",01,"February",02,"March",03,"April",04,"May",05,"June",06,"July",07,"August",08,"September",09,"October",10,"November",11,"December",12);

@output = map{
$pattern=$_;
$pattern =~ s/(.*)\s/$days{$1};
} @dates;

foreach $output (@output)
{
print $output."\n";
}

以下是对我尝试使用此代码的一些解释。

@output将使用新的格式化数组,其中月份名称由在哈希中定义的相应数字代替。

map函数用于动态转换数组元素。

字符序列后跟空格是用于从2011年10月24日的模式中提取月份名称的正则表达式。

这将由$ 1引用。

我使用$ days {$ 1}

在哈希中查找$ 1的相应值

4 个答案:

答案 0 :(得分:4)

我在这看到一些问题。首先是没有use strict;

假设前导零的数字是八进制格式(即基数为8),因此08无效。你想要其中一个:

%days = ("January",     1,  "February",     2,  ...
%days = ("January",   "01", "February",   "02", ...
%days = ("January" =>   1,  "February" =>   2,  ...
%days = ("January" => "01", "February" => "02", ...

您还应该使用my声明变量:

my %days = ...
my @output = ...

你错过了替换的最后一个斜线,你可能希望在那里使用逗号来匹配你想要的输出格式,并且.*会吃掉比你想要的更多:

$pattern =~ s/(\S*)\s/$days{$1}, /;

map的阻止版需要在@output中返回您想要的值,但它当前返回1(请参阅perldoc perlop以了解原因);这样的事情会更好地为你服务:

my @output = map {
    my $pattern=$_; # You don't need this, operating on $_ is fine here
    $pattern =~ s/(\S*)\s/$days{$1}, /;
    $pattern
} @dates;

如果你真的想要从输出中删除空格,那么这应该可以解决问题:

my @output = map {
    my $pattern=$_; # You don't need this, operating on $_ is fine here
    $pattern =~ s/(\S*)\s/$days{$1}, /;
    $pattern =~ s/\s//g;
    $pattern
} @dates;

有更简洁的方法可以做到这一点map但我不想改变太多并且让你感到困惑。

而且,正如评论中所提到的,您可能希望省去一些麻烦并查看DateTime及相关软件包。

答案 1 :(得分:1)

撇开你粘贴非编译代码的事实(忘记训练“/”如sarnold所说),你的正则表达式是错误的。

您使用了GREEDY正则表达式:.* - 意味着在匹配时尽可能多地使用字符。因此,如果October 24,,则正则表达式与October匹配。

您需要\S+\s

答案 2 :(得分:0)

是否要“使用哈希值替换数组元素”,或者是否要将月份名称映射到数字。如果是后者,则以下代码会将month_name day year转换为month_number day year,代码更少:

perl -le '$d=$ARGV[0]; for (qw{Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec}) { $i++; last if $d =~ s/\b$_[^\s]*/$i/i; }; print $d' "october 24, 2011"

答案 3 :(得分:0)

以下是对您的代码的一些反馈:

  • 您粘贴的代码编译得不好。
  • 您没有使用严格和警告。
  • 01至09需要双引号。
  • 您无需在$_声明中重新分配map
  • map需要以您要插入的值结束,例如:map { s/(\w+)/$days{$1}/; $_ }
  • say for @output看起来更好。 =)