如何将 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"}]