【发布时间】:2014-03-01 10:38:00
【问题描述】:
我正在尝试编写一个接受用户输入(一次一行)并以某种方式评估此用户输入的程序。
我有一个函数getline : unit -> string 从标准输入读取一个字符串并返回它。命令格式如下:
#command1 arg1 arg2 arg3
#cmd2 arg1 arg2
#nextcommand arg1 arg2 arg3 arg4
#quit
#exit
对命令的示例调用如下所示:
#command1 2 6 3
#cmd2 6 3
#nextcommand a b3 2 3
主要问题是函数evalcommand : string -> unit 需要getline 获得的整行。我开始了
let evalcommand command = match command with
| "#quit" | "#exit" -> () (* no problem; both length 4 and no arguments *)
| (* how to capture arguments properly? *)
如何处理长度不同的命令(例如 command1 和 cmd2)并且带有附加参数?
已经考虑过不太好的替代方案:
使用解析器(可能由解析器生成器生成):这是我想到的第一件事,但由于我只想支持五六个命令,看起来对我来说有点矫枉过正。
-
检查不同长度的前缀:当然,我可以只检查命令字符串不同长度的前缀,但这似乎涉及很多样板代码。
-
字符串的列表表示:我知道我可以将每个
String转换为char list,然后执行类似的操作let evalcommand command = match String.to_list with | ['#';'e';'x';'i';'t'] -> () (* cumbersome for many commands *) | '#'::'c'::'m'::'d'::'2'::args -> consume_args args (* cumbersome *) | (* and so on *) Mikmatch:我也看过Mikmatch,但如果可能的话,我更喜欢使用 OCaml 的内在特性。
哈希表方法:当然,我可以使用将
Strings 映射到String list -> unit的哈希表(即函数将一定数量的字符串作为参数,返回()) .
所以这是最后一个问题:有没有什么优雅的方法可以以一种直接、易于维护的方式(最好用少量代码)来解决这个问题?
【问题讨论】:
-
如果事情变得更复杂,您可以定义语法并使用
Camlp4.Struct.Grammar模块解析它们。或通过 Lex/Yacc。