2009-07-09 28 views
5

我必須將一個非常大的數據集從一個系統遷移到另一個系統。其中一個「源」列包含日期,但實際上是一個沒有約束的字符串,而目標系統要求格式爲yyyy-mm-dd的日期。「智能」(原諒)日期解析器?

許多(但不是全部)源日期格式爲yyyymmdd。所以,強迫他們到期望的格式,我這樣做(在Perl):

return "$1-$2-$3" if ($val =~ /(\d{4})[-\/]*(\d{2})[-\/]*(\d{2})/); 

當源日期移動從「通用」 YYYYMMDD遠就會出現問題。目標是在放棄之前挽回儘可能多的日期。示例源字符串包括:

21/3/1998,2004年 月, 2001年, 97年3月4日

我可以嘗試儘可能多的實例匹配我可以經常連續發現如上面的表達式。

但是有什麼更聰明的做法嗎?我是不是重新發明輪子?有沒有一個圖書館可以做類似的事情?我找不到任何相關的谷歌搜索「原諒日期解析器」。 (任何語言都可以)。

+0

3/4/97 - 是3月4日還是4月3日? – 2009-07-09 10:50:16

+0

取決於您所在的地區。在美國,那是3月4日。在美國之外,可能在4月3日。 – 2009-07-09 16:42:35

+0

我會想象大多數日期工具將有一種方法來設置如何處理像3/4/97的情況下的默認選項。匆匆一瞥,下面列出的至少兩個Perl模塊都有這樣的選項。 – Telemachus 2009-07-09 17:24:51

回答

2

我終於提取了超過200個實際發生在數據集中的日期示例的測試集。有些人很輕微,有些人完全不舒服(例如「01010」)。

我嘗試了所有現有的Perl模塊,但是成功率太低。我最終潛入我的車輪,成功率超過98%。

我的算法是一系列越來越模糊的識別器,從嚴格有效的日期開始到總猜測區域開始。第一個返回「成功」結果勝出。在該堆棧的中間,我有這樣的「主」識別器:

  • 解析字符串中任意位置的數字組。法語和英語的「月份名稱」也被認可。

  • 對於他們每個人,我把它們放在三個桶裏:候選人一年,候選人一個月,候選人一天。例如,「13」將位於「可能的年份」存儲桶中,並位於「可能的日期」存儲桶中。當然,「二月」只會在「月」桶中出現。在每個存儲桶中,該值都標有「可信度級別」,這是一個取決於許多事物的任意數字。例如,2010年比10年更合理。

  • 看看三個桶中的每一個。如果其中任何一個只有一個項目,則該值爲,該值爲。它也從其他桶中刪除。

  • 按順序(年,月,日)查找其各自桶中剩餘的缺失值,並以最可信度爲準。如果是平局,則取最後一個出現在該字符串中的那個(實際上,這些合理性略高)。這個規則在7月3日作爲3月7日打破,因爲我在法國需要這裏。如果情況適用,請從其他存儲桶中刪除該值。

  • 如果缺少任何值,請使用默認值(例如,我使用8191作爲默認年份,即我的目標系統中允許的最大值)。

整件事非常啓發式,但符合我的要求,最好是有垃圾而不是丟失信息。

4

您是否在尋找Date::Parse模塊?

+0

我不知道perl,但至少在C#中,bogstandard DateTime.TryParse()將接受相當多樣化的不同日期格式。你應該注意那些不接受的東西,並將它們專門化。在這種情況下,整行可能需要手動處理。 – 2009-07-09 10:58:27

4

Date::Manip是你的朋友,因爲是失敗的只有四分之一的,因爲它假定美國的格式,使用Date_Init你可以得到4出的4

如果你有不同的格式(例如,前一天和一個月反之亦然),你必須以不同的方式解析它們,一次使用美國日期格式,另一次使用非美國日期格式。這在模糊的時候尤其重要,比如你的3/4/97例子,因爲如果它是21/3,它就會失敗,你可以告訴格式錯誤。

[email protected]:~$ more date.pl 
use strict; 
use warnings; 
use Date::Manip; 

my @a; 
push @a, "March 2004"; 
push @a, "2001"; 
push @a, "3/4/97"; 
push @a, "21/3/1998"; 
Date_Init("DateFormat=non-US"); 
for my $d (@a) { 
    print "$d\n"; 
    print ParseDate($d)."\n"; 
}; 
[email protected]:~$ perl date.pl 
March 2004 
2004030100:00:00 
2001 
2001010100:00:00 
3/4/97 
1997040300:00:00 
21/3/1998 
0:00:00 
1

您還可以看看DateTime::Format::Flexible

基於其描述,這是對你的衚衕:

如果你曾經不得不使用程序 使你鍵入在某日某種方式和想法「爲什麼不能 計算機只是找出我 想要什麼日期?」,這個模塊是給你的。

DateTime :: Format ::彈性的嘗試到 將您給它的任何字符串和解析 它到一個DateTime對象。

我剛剛使用此模塊運行了Vinko腳本的一個版本,並得到了類似的結果。除了最後一種情況(1998年3月21日),一切都很好。與Date::Manip一樣,您可以通過明確設置參數(european => 1)來相對容易地處理此問題。丹比斯特羅姆的評論顯示了這種情況爲什麼需要人爲疏忽。