2011-10-24 188 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