如何PARSE一个项目序列,其中不在块中的项目像单个元素块一样处理?

时间:2014-02-08 09:16:37

标签: parsing rebol rebol3

我遇到了需要等同的情况,例如:

[
    {Foo}
    http://example.com/some/stuff.html
    separator
]

...的处理就像你写的那样:

[
    [{Foo}]
    [http://example.com/some/stuff.html]
    [separator]
]

添加一点复杂性是,如果你把项放在一个块中,那么它可以有参数:

[
    [{Foo} /some-refinement]
    [http://example.com/some/stuff.html {stuff caption} 3]
    [separator dashed-line]
]

我想要一个基于PARSE的引擎,它可以为{Foo}[{Foo}][{Foo} /some-refinement] 运行相同的处理程序(让我们称之为STRING-HANDLER),并且仅使用正确数量的参数调用它。

在没有PARSE的情况下写这个很容易......一个元素被包装在一个临时块中(如果它不是一个块)。然后在CASE语句中测试第一个项目。但是我想将它转换为基于PARSE的,其中一个分支使用INTO而另一个分支不使用,而不重复代码。

它需要支持嵌套,因此您最终可能会处理以下内容:

[http://example.com/some/stuff.html [{Foo} /some-refinement] 3]

1 个答案:

答案 0 :(得分:1)

我希望以下内容可以作为您解决方案的基础。

以下内容在R2和R3中的表现完全相同。 PARSE的'投入使用在两者之间非常不同所以我放了一个简单的警卫[.here.: block! :.here.]来修复两个平台中不同的错误情况。

我使用了钩子函数,它允许干净地将数据浏览与数据评估分开。如果你仔细观察,你会注意到= enter-block?=:rule是全局的,并且在运行emit-value函数之前设置了切换其含义的代码...所以在某些情况下,你可能真的想要使用emit-value设置不同的规则。

请注意,我不会假设任何类型的已知结构,因为您的解释似乎是针对非结构化数据集的。

另请注意,测试B设置为字符串,因此我们可以直接在字符串输入数据上使用包装器:

rebol [
    author: "Maxim Olivier-Adlhoch"
    date: 2014-02-08
    license: "public domain"
]


A: [
    [{Foo}]
    [http://example.com/some/stuff.html]
    [separator]
]


B: {[
    {Foo}
    http://example.com/some/stuff.html
    separator
]}


C: [
    [{Foo} /some-refinement]
    [http://example.com/some/stuff.html {stuff caption} 3]
    [separator dashed-line]
]


D: [http://example.com/some/stuff.html [{Foo} /some-refinement] 3]


depth: ""
enter-block: func [][
    prin depth 
    print "[" 
    append depth "^-"
]

quit-block: func [][
    remove depth 
    prin depth 
    print "]"
]

emit-value: func [value][
    prin depth 
    probe value
]

=enter-block?=: none

=block=: [
    (
        =enter-block?=: [into =block=] ; we enter blocks by default
        enter-block
    )
    some [
        .here.: block! :.here. ; only enter blocks (R3/R2 compatible)
        (if 1 = length? .value.: first .here. [ =enter-block?=: [skip]  emit-value first .value. ])
        =enter-block?=
        | set .value. skip ( emit-value .value. )
    ]
    (quit-block)
]

STRING-HANDLER: func [data][
    if string? data [
        data: load data
    ]

    parse data =block=
]

STRING-HANDLER A
STRING-HANDLER B
STRING-HANDLER C
STRING-HANDLER D

ask "press enter to quit ..."