如何将 txt 文件中的值解析为 OCaml 中的记录列表?
How do you parse values from a txt file into a list of records in OCaml?
我正在尝试学习 OCaml,但在将文件解析为记录列表时遇到困难。假设我有一个格式如下的文本文件:
吉姆鲍勃,红色
史蒂夫·布莱克,蓝色
等等
我希望能够将 csv 解析为记录列表,稍后我会用它来进行基本的列表操作,例如排序,记录为:
type person_info =
{
name : string;
favorite_color : string;
}
我有解析功能:
let parse_csv =
let regexp = Str.regexp (String.concat "\|" [
"\"\([^\"\\]*\(\\.[^\"\\]*\)*\)\",?";
"\([^,]+\),?";
",";
]) in
fun text ->
let rec loop start result =
if Str.string_match regexp text start then
let result =
(try Str.matched_group 1 text with Not_found ->
try Str.matched_group 3 text with Not_found ->
"") :: result in
loop (Str.match_end ()) result
else
result in
List.rev ((if
try String.rindex text ',' = String.length text - 1
with Not_found -> false
then [""] else [])
@ loop 0 [])
这将为我拆分所有内容。但是我不知道如何将内容读入记录列表,甚至无法将其正确解析为数组:
let () =
let ic = open_in Sys.argv.(1) in
let lines = ref [] in
try
while true do
lines := Array.of_list (parse_csv (input_line ic))
done
with End_of_file ->
close_in ic
无需调用 parse_csv 即可正常工作,但当我尝试解析时失败。
我会像这样在 *nix 系统上启动您的脚本 - 适合测试:
#!/usr/bin/env ocaml
#use "topfind";;
#require "str";;
然后测试你的脚本。错误消息显示
File "./so_howdoyouparse.ml", line 37, characters 13-54:
Error: This expression has type string array
but an expression was expected of type 'a list
下次在您的问题中包含错误消息。
是的,确实,您为什么要将 Array.of_list 分配给用空列表初始化的引用?这一行可以读作:
lines := (parse_csv (input_line ic)) :: !lines
那么你有东西 工作。通过我的编辑(return 行的内容)我得到:
val myresult : string list list =
[["Steve Black"; " blue"]; ["Jim Bob"; " red"]]
您只是忘记使用您的 person_info 记录。
你的代码还有很多问题,比较绕,这个回答旨在帮助你把你的代码做到运行,然后测试和改进。
请注意,您可以使用 opam install csv
安装 exists a CSV module。然后您可以轻松读取文件(在交互式 toploop 中):
# #require "csv";;
/home/chris/.opam/system/lib/csv: added to search path
/home/chris/.opam/system/lib/csv/csv.cma: loaded
# let c = Csv.load "data.csv";;
val c : Csv.t = [["Jim Bob"; "red"]; ["Steve Black"; "blue"]]
然后您可以轻松地将其转换为您喜欢的格式:
# let read_people fname =
Csv.load fname
|> List.map (function [name; favorite_color] -> {name; favorite_color }
| _ -> failwith "read_people: incorrect file");;
val read_people : string -> person_info list = <fun>
# read_people "data.csv";;
- : person_info list =
[{name = "Jim Bob"; favorite_color = "red"};
{name = "Steve Black"; favorite_color = "blue"}]
我正在尝试学习 OCaml,但在将文件解析为记录列表时遇到困难。假设我有一个格式如下的文本文件:
吉姆鲍勃,红色
史蒂夫·布莱克,蓝色
等等
我希望能够将 csv 解析为记录列表,稍后我会用它来进行基本的列表操作,例如排序,记录为:
type person_info =
{
name : string;
favorite_color : string;
}
我有解析功能:
let parse_csv =
let regexp = Str.regexp (String.concat "\|" [
"\"\([^\"\\]*\(\\.[^\"\\]*\)*\)\",?";
"\([^,]+\),?";
",";
]) in
fun text ->
let rec loop start result =
if Str.string_match regexp text start then
let result =
(try Str.matched_group 1 text with Not_found ->
try Str.matched_group 3 text with Not_found ->
"") :: result in
loop (Str.match_end ()) result
else
result in
List.rev ((if
try String.rindex text ',' = String.length text - 1
with Not_found -> false
then [""] else [])
@ loop 0 [])
这将为我拆分所有内容。但是我不知道如何将内容读入记录列表,甚至无法将其正确解析为数组:
let () =
let ic = open_in Sys.argv.(1) in
let lines = ref [] in
try
while true do
lines := Array.of_list (parse_csv (input_line ic))
done
with End_of_file ->
close_in ic
无需调用 parse_csv 即可正常工作,但当我尝试解析时失败。
我会像这样在 *nix 系统上启动您的脚本 - 适合测试:
#!/usr/bin/env ocaml
#use "topfind";;
#require "str";;
然后测试你的脚本。错误消息显示
File "./so_howdoyouparse.ml", line 37, characters 13-54:
Error: This expression has type string array
but an expression was expected of type 'a list
下次在您的问题中包含错误消息。
是的,确实,您为什么要将 Array.of_list 分配给用空列表初始化的引用?这一行可以读作:
lines := (parse_csv (input_line ic)) :: !lines
那么你有东西 工作。通过我的编辑(return 行的内容)我得到:
val myresult : string list list =
[["Steve Black"; " blue"]; ["Jim Bob"; " red"]]
您只是忘记使用您的 person_info 记录。
你的代码还有很多问题,比较绕,这个回答旨在帮助你把你的代码做到运行,然后测试和改进。
请注意,您可以使用 opam install csv
安装 exists a CSV module。然后您可以轻松读取文件(在交互式 toploop 中):
# #require "csv";;
/home/chris/.opam/system/lib/csv: added to search path
/home/chris/.opam/system/lib/csv/csv.cma: loaded
# let c = Csv.load "data.csv";;
val c : Csv.t = [["Jim Bob"; "red"]; ["Steve Black"; "blue"]]
然后您可以轻松地将其转换为您喜欢的格式:
# let read_people fname =
Csv.load fname
|> List.map (function [name; favorite_color] -> {name; favorite_color }
| _ -> failwith "read_people: incorrect file");;
val read_people : string -> person_info list = <fun>
# read_people "data.csv";;
- : person_info list =
[{name = "Jim Bob"; favorite_color = "red"};
{name = "Steve Black"; favorite_color = "blue"}]