OCaml:可变长度字符串上的模式匹配

时间:2014-03-01 10:38:01

标签: pattern-matching ocaml

我正在尝试编写一个接受用户输入的程序(一次一行)并以某种方式评估此用户输入。

我有一个函数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? *)

我如何处理长度不同的命令(例如command1cmd2)并且还有其他参数?

已经考虑过不太好的替代方案:

  • 使用解析器(可能由解析器生成器生成):这是我想到的第一件事,但由于我只想支持五到六个命令,它似乎对我来说太过分了。

  • 检查不同长度的前缀:当然,我可以检查不同长度命令字符串的前缀,但这似乎涉及大量的样板代码。

    < / 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的哈希表(即将一定数量的字符串作为参数的函数,返回())。

所以这是最后一个问题:是否有任何优雅的方式以简单,易于维护的方式解决这个问题(最好用少量的代码)?

2 个答案:

答案 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编写解释器。除非您对嵌套分隔符非常满意,否则您的命令行可能可以用正则表达式来描述。