Haskell 秒差距和无序属性

发布于 2024-09-18 15:21:53 字数 1616 浏览 8 评论 0原文

我正在尝试使用 Parsec 来解析这样的内容:

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

我正在实现 iCalendar 规范,并且在每个 like 上都有一个 name:parameters:value 三元组,非常类似于 XML 具有 name:attributes:content 三元组的方式。事实上您可以非常轻松地转换 iCalendar转换为 XML 格式(我认为我无法真正看到优点)。

我的观点是,参数根本不必按任何顺序出现,并且每个参数可能有不同的类型。一个参数可以是字符串,而另一个参数可以是另一元素的数字 ID。它们可能还没有相似之处,最后,我想将它们正确地放置在我希望解析器返回的任何“SomeObjectInstance”的正确记录字段中。我该如何去做这种事情(或者你能给我举一个例子,说明有人必须解析这样的数据)?

谢谢,我知道我的问题可能有点困惑,但这反映了我对我需要做的事情的理解程度。

编辑:我试图避免给出预期的输出(因为它很大,而不是因为它被隐藏),但这里是一个输入文件的示例(来自维基百科):

开始:VCALENDAR
版本:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
开始:VEVENT
UID:[电子邮件受保护]
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:[电子邮件受保护]
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
摘要:巴士底日派对
结束:VEVENT
结束:V日历

正如您所看到的,它在 VCalendar 中包含一个 VEvent,我制作了 此处代表它们的数据结构

我正在尝试编写一个解析器,将该类型的文件解析为我的数据结构,但我陷入了需要处理以任何顺序、任何类型的属性的困境;日期、时间、整数、字符串、uid 等。我希望这在不重复整个 iCalendar 规范的情况下更有意义。

I am trying to use Parsec to parse something like this:

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

I am implementing the iCalendar spec and on every like there is a name:parameters:value triplet, very much like the way that XML has a name:attributes:content triplet. Infact you could very easily convert an iCalendar into XML format (thought I can't really see the advantages).

My point is that the parameters do not have to come in any order at all and each paramater may have a different type. One parameter may be a string while the other is the numeric id of another element. They may share no similarity yet, in the end, I want to place them correctly in the right record fields for whatever 'SomeObjectInstance' that I wanted the parser to return. How do I go about doing this sort of thing (or can you point me to an example of where somebody had to parse data like this)?

Thankyou, I know that my question is probably a little confused but that reflects my level of understanding of what I need to do.

Edit: I was trying to avoid giving the expected output (because it is large, not because it is hidden) but here is an example of an input file (from wikipedia):

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:[email protected]
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR

As you can see it contains one VEvent inside a VCalendar, I have made data structures that represent them here.

I am trying to write a parser that parses that type of file into my data structures and I am stuck on the bit where I need to handle properties coming in any order with any type; date, time, int, string, uid, ect. I hope that makes more sense without repeating the entire iCalendar spec.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梓梦 2024-09-25 15:21:54

Parsec 具有 Parsec.Perm 模块,可以精确地解析无序但线性(即在语法树中的同一级别)元素,例如 XML 文件中的属性标记。

不幸的是 Perm 模块大多没有文档记录。最好的参考是 Haddock 文档页面引用的 Parsing Permutation Phrases 论文,但即便如此,这很大程度上也是对该技术的描述,而不是如何使用它。

Parsec has the Parsec.Perm module precisely to parse unordered but linear (i.e. at the same level in the syntax tree) elements such as attribute tags in XML files.

Unfortunately the Perm module is mostly undocumented. The best reference is the Parsing Permutation Phrases paper which the Haddock doc page refers to, but even that is largely a description of the technique rather than how to use it.

离线来电— 2024-09-25 15:21:54

好的,在 BEGIN:VEVENTEND:VEVENT 之间,您有许多键值对。因此,编写一个返回 (key, value) 的规则 keyValuePair。现在,在 VEVENT 规则中,您执行 many KeyValuePair 来获取对的列表。完成此操作后,您可以使用折叠来使用给定值填充 VEVENT 记录。在您提供给折叠的函数中,您使用模式匹配来找出在哪个字段中存储该值。您使用 VEvent 记录作为累加器的起始值,其中可选字段设置为 Nothing。例如:

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

Ok, so between BEGIN:VEVENT and END:VEVENT, you have many key value pairs. So write a rule keyValuePair that returns (key, value). Now inside the rule for VEVENT you do many KeyValuePair to get a list of pairs. Once you've done that you use a fold to populate a VEVENT record with the given values. In the function you give to fold, you use pattern matching to find out in which field to store the value. As the starting value for the accumulator you use a VEvent record where the optional fields are set to Nothing. Example:

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}

...and so on. Do the same for the other components.

Edit: Here's some runnable example code for the fold:

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")]

Output:

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

Note that this will produce a warning when compiled. To avoid the warning, initialize all non-optional fields to undefined explicitly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文