2013-03-11 83 views
3

我有一個問題啓發式解析一個包含日期,但在一個相當任意(未知)格式的文本字符串。啓發式(模糊)從字符串中提取日期?

function parseDateStr($text) { 
    $cleanText = filter($text); 
    # ... 
    $day = findDay($cleanText); 
    $month = findMonth($cleanText); 
    $year = findYear($cleanText); 
    # .. assert constraints, parse again or fail 
    return sprintf('%04d-%02d-%02d', $year, $month, $day) 
} 

輸入文本是英語語言加上任意語法符號(如\ W RegExp類的子集)的句子。該算法的任務是僅在過濾掉與日期無關的任何可能的垃圾(嘈雜)字詞後才提取日期。允許該算法失敗並返回任何結果。如果在字符串中只找到兩個連接的數字(MM)和四個其他數字(YYYY)的兩個組合 - 假定兩個數字對應於日期的月份,並且日期取爲01(第一天這個月)。結果以「YYYY-MM-DD」(SQL)格式(DATE類型)給出日期。

我的想法是繼續設計一系列使用preg_replace & co。此外,對$ year,$ day的範圍使用邏輯約束,對$ month等使用詞彙表,但如果類似但更優雅的解決方案或方法是可想或已存在的,我不會感到驚訝。如果是這樣,請讓我知道他們。我也希望能夠指出任何批評者或潛在的陷阱。

關係到類似的問題:

請注意,這個問題是從更基本的日期解析問題不同:

,因爲在我的我無法指定或確定字符串的格式。在另一方面以下幾個問題談類似的任務:

我不知道如果最後一個是重複的,它不是最終明確對我想要解析的OP(儘管檢查日期date_parse似乎部分有用)。但在整個「mokey企業」的第一個問題也是我的情況屬實,並已被模糊解析爲

dparser.parse("monkey 2010-07-10 love banana",fuzzy=True) 

最後解決,第二個包含大正則表達式(幾乎是「模糊」) 。

PS by elegant我明白代碼非常緊湊(對性能沒有明顯的限制,所以使用「hacky」正則表達式可以)。

+0

正如您在其中一個鏈接中提到的那樣,您如何解析1/2/3?我認爲你需要解析的字符串的例子可以證明是有幫助的,或者它就像用戶輸入並且是完全隨機的?最後,我認爲反對hacky正則表達式的主要觀點通常不是性能(除非針對大型字符串運行*很多次),但代碼維護和易於出錯。 – kjetilh 2013-03-11 23:15:29

+0

@kjetilh點採取。我將盡快提供示例輸入的列表以及我的部分解決方案代碼。 – 2013-03-11 23:18:31

+0

是的,** var_dump(date_parse(「Joe Soap出生於1981年2月12日」)); **似乎已經做得非常好。 – 2013-03-11 23:23:55

回答

4

timelib

好,date_parse正在執行非常非常好,這是很有教育意義的學習爲什麼。 PHP函數date_parseext/date/libtimelib,顯然的一部分(儘管缺少適當的文件)其C實現(由德里克Rethans的書面和從聲明的Zend引擎宏一部分調用)使它成爲一個聰明的工具:

  1. date_parse已經模糊:有很多的警告(和抱怨),其功能容忍和分析太多,但顯然它實際上是一個功能,而不是錯誤的文檔頁面上(否則應該使用date_parse_from_format或相應的日期時間:: createFromFormat()
  2. date_parse使用(很多)在相對智能的方式正則表達式(基於re2c
  3. 除了過濾這種「掃描儀」尋找所有可能的單詞和日期格式的組合(來自已知月份和時區的列表),最後,通過分別查找「YYYY」,「MM」和「DD」(與我需要做的非常相似)來進行「盲目」猜測。
  4. date_parse是一個真正的編譯「掃描儀」,帶有先行邏輯和錯誤報告,可以由用戶進一步處理(無例外,只是嵌套數組結果中的消息)。
  5. 甚至有一個python package包裝timelib的C代碼(所以我甚至不知道這是「解析猴子生意」 timelib蟒蛇,dateutil在最終更好)

測試和例子

從我個人而言,我並沒有發現從我的數據集不是由date_parse解析,即任何輸入例如:

echo FuzzyDateParser::fromText('banana 1/2/3'); 
echo FuzzyDateParser::fromText('Joe Soap was born on 12 February 1981')); 
echo FuzzyDateParser::fromText('2005 Feb., reprint')); 
echo FuzzyDateParser::fromText('!'); # will fail to parse, producing an empty string. 
echo FuzzyDateParser::fromText('monkey 2010-07-10 loves bananas and php'); 

FuzzyDateParser類的代碼可以在gist中找到。它可以作爲一個模板來處理錯誤,並實現從自定義邏輯(我最終不需要爲我的情況做)爲結果的date_parse回退。

+0

偉大的要點,謝謝! – Sam 2018-02-07 12:39:53