2010-09-14 61 views
6

我試圖用秒差距來分析是這樣的:哈斯克爾秒差距和無序屬性

property :: CharParser SomeObject 
property = do 
    name 
    parameters 
    value 
    return SomeObjectInstance { fill in records here } 

我實施的iCalendar規範,對每一個喜歡有一個名字:參數:值三峯,非常喜歡XML具有名稱的方式:attributes:content triplet。 Infact you could very easily convert an iCalendar into XML format(以爲我看不出優點)。

我的觀點是,參數不必以任何順序出現,每個參數可以有不同的類型。一個參數可能是一個字符串,而另一個參數可能是另一個元素的數字ID。他們可能沒有共同點,最後,我想把它們正確地放在正確的記錄字段中,以便解析器返回任何'SomeObjectInstance'。我該如何去做這類事情(或者你能指點我一個例子,說明有人必須像這樣解析數據)?

謝謝,我知道我的問題可能有點困惑,但這反映了我對我需要做什麼的理解程度。

編輯:我試圖避免給出預期輸出(因爲它是大的,而不是因爲它是隱藏的),但這裏是一個輸入文件(來自維基百科)的例子:

BEGIN :VCALENDAR
VERSION:2.0
PRODID: - // hacksw/handcal // NONSGML 1.0 // EN
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19970714T170000Z
組織者; CN = John Doe的:MAILTO:[email protected]
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
內容:巴士底日方
END:VEVENT
END:VCALENDAR

正如你可以看到它在VCalendar中包含一個VEvent,我已經制作了data structures that represent them here

我想寫一個解析器,將該類型的文件解析爲我的數據結構,並且卡在需要處理任何類型的任何順序的屬性的位上;日期,時間,int,字符串,uid等。我希望在不重複整個iCalendar規範的情況下更有意義。

+0

我不確定你在問什麼。你能舉一個可能的輸入和預期輸出的例子嗎? – sepp2k 2010-09-14 04:42:03

+0

我給了更多的信息,我希望它現在更有意義,您已經預期了輸入以及我試圖用解析器填充的數據結構。現在我只是想弄清楚如何用parsec來做到這一點。 – 2010-09-14 04:51:37

回答

6

Parsec擁有Parsec.Perm模塊,可以精確地解析XML文件中的無序但線性(即與語法樹中的同一級別)元素,如屬性標記。

不幸的是,Perm模塊大部分都是無證的。最好的參考文獻是Haddock doc頁面提到的Parsing Permutation Phrases論文,但即使這樣,這在很大程度上也是對技術的描述,而不是如何使用它。

+0

你是對的,那是很好的建議。我會盡快閱讀那篇文章,如果事實證明正是我所需要的,那麼我甚至可以寫一篇博客文章。 – 2010-09-14 10:23:33

+0

解析排列短語的第5節中有兩個例子。最初的Parsec手冊也有一個簡單的例子 - 它可能仍然有幫助,因爲Parsec和PPP文件的組合名稱不同。 Parsec手冊可在這裏找到: http://legacy.cs.uu.nl/daan/parsec.html – 2010-09-14 11:36:09

+1

對於其他尋找解決這類問題的解決方案的人,Robert確實寫了一篇關於該主題的博文: http://robertmassaioli.wordpress.com/2010/09/15/unordered-parsing-in-parsec/不幸的是,博客軟件似乎在剝離某些人物。我已經添加了缺失的位並將其發佈到此處:http://hpaste.org/46655/simple_example_of_parsec_perm感謝您編寫了一個簡單的示例Robert。 – 2011-05-13 15:18:50

1

好的,所以在BEGIN:VEVENTEND:VEVENT之間,你有很多關鍵值對。因此,編寫一個返回(key, value)的規則keyValuePair。現在在VEVENT的規則內,您可以使用many KeyValuePair來獲取配對列表。一旦你完成了,你使用fold來填充給定值的VEVENT記錄。在你給摺疊的函數中,你使用模式匹配來找出在哪個字段存儲值。作爲累加器的起始值,您可以使用可選字段設置爲Nothing的VEvent記錄。例如:

pairs <- many keyValuePairs 
vevent = foldr f (VEvent {sequence = Nothing}) pairs 
    where f ("SUMMARY", v) ve = ve {summary = v} 
      f ("DSTART", v) ve = ve {dstart = read v} 

...等等。對其他組件做同樣的事情。

編輯:下面是摺疊的一些可運行的示例代碼:

data VEvent = VEvent { 
     summary :: String, 
     dstart :: String, 
     sequenceSt :: Maybe String 
     } deriving Show 

vevent pairs = foldr f (VEvent {sequenceSt = Nothing}) pairs 
    where f ("SUMMARY", v) ve = ve {summary = v} 
      f ("DSTART", v) ve = ve {dstart = v} 
      f ("SEQUENCEST", v) ve = ve {sequenceSt = Just v} 

main = do print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu")] 
      print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu"), ("SEQUENCEST", "lili")] 

輸出:

VEvent {summary = "lala", dstart = "lulu", sequenceSt = Nothing} 
VEvent {summary = "lala", dstart = "lulu", sequenceSt = Just "lili"} 

注意,在編譯時,這將產生一個警告。爲避免此警告,請明確將所有非可選字段初始化爲undefined

+0

這與我最初想到的類似,但你如何決定什麼是「零」?你把'零'作爲'VEvent {sequence = Nothing}',但是如果結構比我所做的更復雜,如果它有一堆必須設置的整數字段,不想讓每個記錄字段成爲可能。你能否在一開始就製作多個你不需要的必填字段? (讓我知道如果我需要更好地描述這個新問題,我會嘗試提供一個代碼示例) – 2010-09-14 05:51:11

+0

@Robet:正如我所說的,將可選項初始化爲Nothing。其他的你根本不需要初始化。如果沒有可選的'Vevent {}'將是一個非常好的初始值(或者你可以顯式地將每個非可選值設置爲undefined以避免發出警告,但是我想這會讓很多字段變得厭倦) 。 – sepp2k 2010-09-14 05:54:07

+0

雖然這對我來說不成功? http://pastie.org/1157529 – 2010-09-14 05:56:14