parse函数转换的语法主要根据控制流进行改变,提到Rebol语言的优秀特性那就不得不说它的解析引擎,简称Parse。这项来自Carl Sassenrath的伟大设计,在过去的15年里,使得Rebol用户免受正则表达式(以不可维护著称)的折磨。现如今,Parse的增强版本在Red语言中重装上阵。

简而言之,Parse是一个使用语法规则来解析输入序列的内部DSL(在Rebol生态圈称为“方言”)。Parse方言是TDPL家族的突出一员。常用来校验,验证,分解,修改输入的数据,甚至是实现内部或者外部DSL。

parse函数的用法很简单:

bitset. 实现并支持DSL的发展:

parse <输入序列> <规则> <输入序列>: 任意序列类型的值(字符串,文件,区块,路径...) <规则>: 一个区块(包含有效的Parse方言)123123

下面的示例代码可以直接复制到Red控制台中运行,即便你不懂Red和Parse方言,也能观其大略,不像正则表达式那样让人不知所云。

使用语法规则验证一些字符串和区块的输入:

parse "a plane" [["a" | "the"] space "plane"] 规则中可以包含子规则 parse "the car" [["a" | "the"] space ["plane" | "car"]] parse "123" ["1" "2" ["4" | "3"]] parse "abbccc" ["a" 2 "b" 3 "c"] 指定数量 parse "aaabbb" [copy letters some "a" (n: length? letters) n "b"] 将匹配绑定到变量,使用小括号执行Red表达式 parse [a] ['b | 'a | 'c] parse [hello nice world] [3 word!] 匹配区块可以使用类型 parse [a a a b b b] [copy words some 'a (n: length? words) n 'b]1234567891012345678910

下面展示如何解析IPv4地址:

four: charset "01234" charset函数用于创建一个bitset!类型的值 half: charset "012345" non-zero: charset "123456789" digit: union non-zero charset "0" bitset!类型可以使用Red的集合运算union函数进行组合 byte: [ "25" half | "2" four digit | "1" digit digit | non-zero digit | digit ] ipv4: [byte dot byte dot byte dot byte] parse "192.168.10.1" ipv4 parse "127.0.0.1" ipv4 parse "99.1234" ipv4 parse "10.12.260.1" ipv4 data: { ID: 121.34 Version: 1.2.3-5.6 Your IP address is: 85.94.114.88. NOTE: Your IP Address could be different tomorrow. } parse data [some [copy value ipv4 | skip]] probe value 输出: "85.94.114.88"123456789101112131415161718192021222324252627123456789101112131415161718192021222324252627

一个粗糙然而实用的email地址验证器:

digit: charset "0123456789" letters: charset [#"a" - #"z" #"A" - #"Z"] special: charset "-" chars: union union letters special digit word: [some chars] host: [word] domain: [word some [dot word]] email: [host "@" domain] parse "john@doe.com" email parse "n00b@lost.island.org" email parse "h4x0r-l33t@domain.net" email123456789101112123456789101112

验证字符串形式的数学表达式(来自Rebol/Core手册)

expr: [term ["+" | "-"] expr | term] 规则可以递归定义 term: [factor ["*" | "/"] term | factor] factor: [primary "**" factor | primary] primary: [some digit | "(" expr ")"] digit: charset "0123456789" parse "1+2*(3-2)/4" expr 返回 true parse "1-(3/)+2" expr 返回 false1234567812345678

创建简单的解析器用于解析一个HTML子集:

html: { <html> <head><title>Test</title></head> <body><div><u>Hello</u> <b>World</b></div></body> </html> } ws: charset reduce [space tab cr lf] parse html tags: [ collect [any [ ws | "</" thru ">" break | "<" copy name to ">" skip keep (load name) opt tags | keep to "<" ]] ] parse函数将会返回如下区块树 [ html [ head [ title ["Test"] ] body [ div [ u ["Hello"] b ["World"] ] ] ] ]12345678910111213141516171819202122232425262728293031321234567891011121314151617181920212223242526272829303132

Parse方言,parse/trace <输入> <规则> <回调函数>

<回调函数> 规格:

func [

event [word!] 跟踪事件

match? [logic!] 上次匹配操作的结果

rule [block!] 当前位置的对应规则

input [series!] 将要匹配的下一个位置的输入序列

stack [block!] 内部的解析规则栈

return: [logic!] TRUE: 继续匹配, FALSE: 退出

]

事件列表:

- push : 当一个规则或者区块入栈时

- pop : 当一个规则或者区块出栈之前

- fetch : 当一个新的规则被采用之前

- match : 当一个值匹配发生了

- iterate : 当一个新的迭代开始了 (ANY, SOME, ...)

- paren : 当一个小括号中的表达式被求值后

- end : 当到达输入末尾时。