我有文本为"[(1,2); (3,4); (5,6)]"
的文件“ example.dat”。我需要从中获取元组列表。我知道,如何从整数列表中获取它。
# let f line = List.map int_of_string line;;
# open Printf
let file = "example.dat"
let () =
let ic = open_in file in
try
let line = input_line ic in
f line;
flush stdout;
close_in ic
with e ->
close_in_noerr ic;
raise e;;
我必须如何更改功能?
答案 0 :(得分:0)
给出一个表示整数的字符串列表,您的函数f
返回一个整数列表。它不返回元组列表。
您没有说是否要验证输入是否具有某种正确的形式。如果要验证其是否具有OCaml中类型为(int * int) list
的列表的形式,则这是一个解析问题,将需要一些工作。
如果只想提取输入行中看起来像整数的部分,则可以从Str
模块中使用正则表达式处理:
# let re = Str.regexp "[^0-9]+" in
Str.split re "[(1,2); (37,4); (5,6)]";;
- : string list = ["1"; "2"; "37"; "4"; "5"; "6"]
然后,您可以重写函数f
,以将每对整数收集到一个元组中。我看不出使用List.map
的好方法。您可能必须编写自己的递归函数或使用List.fold_left
。
更新
我将为您编写一个将值列表更改为成对列表的函数。我希望这不是给学校做作业,在这种情况下,您应该自己弄清楚这一点。
let rec mkpairs l =
match l with
| [] | [_] -> []
| a :: b :: rest -> (a, b) :: mkpairs rest
如您所见,如果列表中元素的数量为奇数,则此函数会默默地丢弃列表的最后一个元素。
此函数不是尾部递归的。因此,您可以考虑进行改进。
答案 1 :(得分:0)
let open Genlex in
let open Stream in
let lexer = make_lexer ["["; "("; ","; ")"; ";"; "]";] in
let stream = lexer (of_string array_string) in
let fail () = failwith "Malformed string" in
let parse_tuple acc = match next stream with
| Int first -> ( match next stream with
| Kwd "," -> ( match next stream with
| Int second -> ( match next stream with
| Kwd ")" -> (first, second) :: acc
| _ -> fail () )
| _ -> fail () )
| _ -> fail () )
| _ -> fail ()
in
let rec parse_array acc =
match next stream with
| Kwd "(" -> parse_array (parse_tuple acc)
| Kwd ";" -> parse_array acc
| Kwd "]" -> acc
| _ -> fail ()
in
try
match next stream with
| Kwd "[" -> List.rev (parse_array [])
| _ -> fail ()
with Stream.Failure -> fail ();;