FParsec 是一个F#语言构建的解析器组合库,主要用于解析文本,并结构化输出,可以为形式语法实现递归下降文本解析器。根据官网的介绍,FParsec库的主要功能包括:
- 支持上下文相关的无限前瞻文法
- 自动生成、高度可读的错误消息
- Unicode 支持
- 对非常大的文件的有效支持
- 一个可嵌入的、运行时可配置的运算符优先级解析器组件
- 一个简单、高效且易于扩展的 API
- 针对性能进行彻底优化的实现
- 全面的文档
- 一个宽松的开源许可证,源代码和二进制形式的 FParsec 库是在简化的 BSD 许可下分发
官网为 http://www.quanttec.com/fparsec/ ,可以从官网查看具体的用法。FParsec 源代码在 GitHub 上可以下载:github.com/stephan-tolksdorf/fparsec
FParsec 库的源代码用 C# 和 F# 编写的,包含两个DLL库:FParsec.dll和 FParsecCS.dll ,项目需要引用此DLL库。下面给出一些示例,用来直观的掌握如何使用这个解析器库:
首先,所有 FParsec 类型和模块都在FParsec
命名空间中声明。该命名空间包含一些基本类和4个 F# 模块,即:
Primitives
:包含基本类型定义和解析器组合器CharParsers
:包含字符、字符串和数字的解析器,以及将解析器应用于输入流的函数Error
:包含用于创建、处理和格式化解析器错误消息的类型和辅助函数StaticMapping
:包含将静态键值映射编译为优化函数的函数
因此如果要使用open FParsec库,则应该首先引入此库:
openFParsec
首先需要需要根据解析的对象,构建合适的解析器Parser,当然,FParsec库中的模块如 FParsec.Primitives和FParsec.CharParsers模块中包含了内置的解析器,如解析float类型的解析器pfloat,其定义为:
valpfloat: Parser<float,'u>
如果要想调用此解析器,并返回结果(ParserResult<'Result,unit>),则需要run来进行调用 ,其中的ParserResult定义为:
typeParserResult<'Result,'UserState>=|Successof'Result * 'UserState*Position|Failureofstring*ParserError*'UserState
解析器pfloat示例为:
letf2=runpfloat"1.25"printfn"%O"f2//Success: 1.25
当然,为了方便的进行测试运行,可以构建一个test函数:
lettestpstr=matchrunpstrwith|Success(value, _, _) ->printfn"OK: %A"value|Failure(err, _, _) ->printfn"Fail: %s"err
用此test函数来运行pfloat解析器示例,如下所示:
//解析float类型testpfloat"1.25"//OK: 1.25testpfloat"1.25E"//Fail: Error ...
其中对文本"1.25E"解析会出现如下错误信息:
Fail: ErrorinLn: 1Col: 61.25E^Note: Theerroroccurredattheendoftheinputstream. Expecting: decimaldigit
下面介绍一下如何从括号中提取数值,示例如下:
//解析string类型,忽略空白 ' ', '\t', '\r' ', '\n' letpstr_wss=pstrings .>>spacesletpfloat_ws=pfloat .>>spaces//()中间的解析出floatletpfloatBetKK=pstr_ws"(">>. pfloat_ws .>>pstr_ws")"testpfloatBetKK"(2.6)"//OK: 2.6testpfloatBetKK"(2.7 )"//OK: 2.7testpfloatBetKK"( 2.8 ) "//OK: 2.8testpfloatBetKK" ( 2.9 ) "//Fail: Error... 左括号有空格
另外,还可以对特定括号中的字符按照分隔符进行拆分并解析,具体示例如下:
letparray=pstr_ws"[">>. sepBypfloat_ws (pstr_ws";") .>>pstr_ws"]"//OK: [1.0; 2.0; 3.0]testparray"[ 1 ; 2 ;3 ] "
有时候,我们解析字符时,希望跳过特定字符,具体示例如下:
//spaces >>. 左空白 .>> spaces 右空白letpfloat_ws2=spaces>>. pfloat .>>spacesletfs= (skipStringCI"<float>">>. pfloat_ws2) stestf"<FLOAT> 1.0 "//OK:1.0
上述示例,则跳过<float>字符串,且忽略大小写,从而提取出1.0