2011-10-24 132 views
3

我正在尝试编写一个Perl脚本,它将采用Pattern中的日期,2011年10月24日并将其转换为10,24,2011。用散列值替换数组元素

为了做到这一点,我准备了一个Hash,它将月份名称作为一个关键字,并将一个数值表示月份的位置作为一个值。

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

将本月的名称替换为与该月对应的值作为关键字。

下面是我编码到目前为止的脚本,但它不适用于我。

@dates阵列将每个元素在这个格式 - > 10月24日,2011年

%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函数用于实时转换数组的元素。

字符,随后空间的序列是用于从图案,10月24日提取月份名称的正则表达式,2011.

这将减少$ 1所引用。

我用,$天{$ 1}

+7

为什么不使用'DateTime'? – CanSpice

+1

“不工作”是什么意思?它在'$ pattern =〜s /(。*)\ s/$ days {$ 1};' - 你错过了第三个'/'字符看起来像一个简单的语法错误 - 但它会更容易如果您提供完整的小脚本,请提供反馈意见。 (顺便说一句,CanSpice建议使用'DateTime'是一个很好的建议,尽管我个人发现在某些Linux发行版中可以很容易地使用_some_ date模块,其他的其他日期模块也很容易使用,所以稍加研究一下可能是值得的) – sarnold

+0

考虑将'map'语句写成s /../../ for my @output = @dates;' –

回答

4

我在这里看到了一些问题查找$ 1的对应值的哈希值。首先是没有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需求retur n您想要的值在@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及相关软件包。

+0

非常感谢您的详细解释。是的,我总是使用strict和使用my声明的变量进行编程。在这里,我只想粘贴片段来检查逻辑。你已经给出了一个非常好的清晰的解决方案。 +1 –

1

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

您使用了GREEDY正则表达式:.* - 意思是在匹配时尽可能多的字符。所以你的正则表达式匹配October 24,而不是October

你需要做的\S+\s

+0

谢谢,是的,REGEX是贪婪的,但我不确定解决方法。 –

+0

有两个 - 或者不使用这么宽的匹配(换句话说,我的答案 - 将“。”改为“\ S”) - 或者,可以使用非贪婪的正则表达式。 “perldoc perlre”是你的朋友。 – DVK

0

你想“与哈希值代替数组元素,”还是你想一个月名号映射。如果是后者,下面就转换到month_name day yearmonth_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" 
+0

在不到20分钟的时间里,我得到了超过4个解决方案。谢谢,你们很快! :)我会更多地了解这些功能。 –

+0

@ NeonFlash:np :) – MisterEd

0

这里是你的代码的一些反馈:

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

是的,这只是一个片段,我没有发布严格使用完整的东西,使用警告和使用我的声明变量。然而,当我编程时,我确实记住了这些要点:)另外,我找出了八进制数字的错误并修正了它。感谢您的反馈:) –

+0

@NeonFlash欢迎您。 – TLP

+0

@TLP - 'say'不能与旧的Perl版本一起使用。 OP没有标明他的。在'map'内重新分配'$ _'当然不是必需的,但为了可读性,如果该值将被多次使用,通常是一种很好的做法。其余的都很棒。 – DVK