我有一组特定领域(会计报告)的半结构化TEXT文档,它们在内容上都非常相似。但是,数据在每个文档模板上以不同的方式处理。
编写一些正则表达式并获得我想要的数据是相当容易的。但是对于每个新的文档布局都必须这样做。
我想建立一个通用的解析器,接收一个脚本,它应该如何读取一个特定布局的会计报告,所以对于每一个新的布局,我需要做的就是写一个新的脚本,这比写很多正则表达式更简单。
像这样:
解析脚本:declare collection_name {
date,
description,
amount
}
get customer_name from line 3
get account_id from "AccountID <number>"
read data as <collection_name> from <pattern> until <pattern>
请给我任何线索,从哪里开始,读什么关于它,或者如果你已经看到类似的东西。我将非常感谢您的帮助。
构建DSL并不是一件容易的事情,尤其是像你提议的那样使用丰富的语法,所以我认为你已经准备好了:)
管道为:
Script -> Compiler -> PHP code for specific template
然后使用PHP代码获取数据
TEXT -> PHP code for that template -> data(structured JSON,XML,...)
所以要构建编译器,你需要理解流程:
Script -> Lexer(Tokenizer) -> Parser -> AST/CFG -> PHP code generation
定义https://stackoverflow.com/a/380487/877594
Tokenizer将文本流分解为标记,通常通过查找空白(制表符,空格,新行)
Lexer基本上是一个标记器,但它通常为标记附加额外的上下文——这个标记是一个数字,那个标记是一个字符串文字,另一个标记是一个相等运算符。
Parser从词法分析器获取令牌流,并将其转换为抽象语法树,表示(通常)由原始文本表示的程序。
抽象语法树http://en.wikipedia.org/wiki/Abstract_syntax_tree
源代码抽象语法结构的树状表示用编程语言编写的代码。树的每个节点表示发生在源代码中的结构。语法是"抽象的"没有表示实际语法中出现的每个细节。为实例中,分组括号在树结构中是隐式的,并且像if-condition-then表达式这样的语法结构可能是用带有两个分支的单节点表示
如果您考虑在DSL中使用表达式,则它们适用于表达式而不是指令。
控制流图http://en.wikipedia.org/wiki/Control_flow_graph
使用图表示法表示所有可能的路径在程序执行过程中遍历的
每个节点是一个带有属性的指令对象(declare, get, read,…)。如:
get {
target: customer_name,
from: line {n: 3}
}
建设PHP是一个非常糟糕的选择,因为没有高质量的库来构建词法分析器和解析器,比如C/c++中的Flex/Bison。在这个问题上有一些工具,但我不推荐他们在PHP中使用Flex/bison之类的功能。
我建议你自己构建它:
- Lexer(Tokenizer)这可能有帮助http://nitschinger.at/Writing-a-simple-lexer-in-PHP
- 修改语法,改成
LL(1)
(http://en.wikipedia.org/wiki/LL_grammar) 编写带有错误检查和符号表的解析器来存储变量 - 在解析 时生成控制流图
- 将控制流图转换为PHP代码,将每条指令转换为PHP代码