我正在尝试编写一个接受用户输入的程序(一次一行)并以某种方式评估此用户输入。
我有一个函数getline : unit -> string
,它从stdin读取一个字符串并返回它。命令具有以下格式:
#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
)并且还有其他参数?
使用解析器(可能由解析器生成器生成):这是我想到的第一件事,但由于我只想支持五到六个命令,它似乎对我来说太过分了。
检查不同长度的前缀:当然,我可以检查不同长度命令字符串的前缀,但这似乎涉及大量的样板代码。
< / LI> 列出字符串的表示形式:我知道我可以将每个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的内在功能。
哈希表方法当然我可以使用将String
映射到String list -> unit
的哈希表(即将一定数量的字符串作为参数的函数,返回()
)。
所以这是最后一个问题:是否有任何优雅的方式以简单,易于维护的方式解决这个问题(最好用少量的代码)?
答案 0 :(得分:4)
不是最优雅的解决方案,但为什么不简单地拆分空间?
open Str;;
let split_on_spaces s = split (regexp " ") s;;
let evalcmd cmd = match (split_on_spaces cmd) with
| ["#quit"] | ["#exit"] -> ()
(* match on a known number on arguments *)
| ["#command";arg1;arg2;arg3] -> ()
(* unknown number *)
| "#cmd2" :: arg_list -> ()
答案 1 :(得分:2)
我写了许多简单的命令解释器,正如Marth所说。我认为这是一个优雅的解决方案,可以快速获得简单的命令行语法。
如果您的命令行语法可能比您显示的更丰富(如果您可能需要引用的字符串,比如说),您可以使用ocamllex编写解释器。除非您对嵌套分隔符非常满意,否则您的命令行可能可以用正则表达式来描述。