我有文件“example.dat”,其中包含文本
"[(1,2); (3,4); (5,6)]"
。我需要从中获取元组列表。我知道,如何从整数列表中获取它。
# 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;;
我必须如何改变我的职能?
给定一个表示整数的字符串列表,您的函数
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
如您所见,如果列表有奇数个元素,则此函数会默默地丢弃列表的最后一个元素。
该函数不是尾递归。所以这是你可以考虑改进的地方。
let parse_array_string array_string =
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 ();;