web-dev-qa-db-ja.com

OCamlのテキストファイルから行を読み取るにはどうすればよいですか?

これは私が今まで持っているものです。必要なのはこれだけではありませんか? 「エラー:バインドされていないモジュール標準」というエラーが表示され続ける

let r file =
    let chan = open_in file in
    Std.input_list (chan)
17
Travis

Extlib がインストールされていない場合(そして明らかに上記のエラーメッセージに基づいていない場合)、通常は次のように実行されます。

let read_file filename = 
let lines = ref [] in
let chan = open_in filename in
try
  while true; do
    lines := input_line chan :: !lines
  done; !lines
with End_of_file ->
  close_in chan;
  List.rev !lines ;;

Extlibをお持ちの場合:

let read_file filename =
  let chan = open_in filename in
  Std.input_list chan

...これはほとんどあなたが持っているものです。

Batteries-included ライブラリがある場合は、ファイルをEnum.tに読み込んで、次のように繰り返すことができます。

let filelines = File.lines_of filename in
Enum.iter ( fun line -> (*Do something with line here*) ) filelines
22
aneccodeal

OCaml Coreライブラリがインストールされている場合は、次のように簡単です。

open Core.Std
let r file = In_channel.read_lines file

corebuildがインストールされている場合は、それを使用してコードをコンパイルできます。

corebuild filename.byte

コードがfilename.mlという名前のファイルにある場合。

OCaml Coreがない場合、インストールしたくない場合、またはその他の標準ライブラリ実装の場合は、もちろん、VanillaOCamlの標準ライブラリを使用して実装できます。 Pervasivesモジュールで定義された関数input_lineがあり、これはすべてのOCamlプログラムで自動的に開かれます(つまり、モジュール名でさらに明確にすることなく、すべての定義にアクセスできます)。この関数は、タイプin_channelの値を受け入れ、チャネルから読み取られた行を返します。この関数を使用すると、必要な関数を実装できます。

let read_lines name : string list =
  let ic = open_in name in
  let try_read () =
    try Some (input_line ic) with End_of_file -> None in
  let rec loop acc = match try_read () with
    | Some s -> loop (s :: acc)
    | None -> close_in ic; List.rev acc in
  loop []

この実装は再帰を使用し、OCamlプログラミングにとってはるかに自然です。

16
ivg

これにより、ファイルの行が読み取られ、それぞれが出力されます。

open Core.Std

let handle_line line =
  printf "Your line: %s \n" line

let () =
  let file_to_read = "./file_to_read.txt" in
    let lines = In_channel.read_lines file_to_read in
      List.iter ~f: handle_line lines
2
Matthias Braun

これは、行を蓄積したり外部ライブラリを使用したりしない単純な再帰的ソリューションですが、行を読み取り、関数を使用して処理し、完了するまで次を再帰的に読み取り、正常に終了することができます。 exit関数は、開いているファイルハンドルを閉じ、呼び出し元のプログラムに成功を通知します。

let read_lines file process =
  let in_ch = open_in file in
  let rec read_line () =
    let line = try input_line in_ch with End_of_file -> exit 0
    in (* process line in this block, then read the next line *)
       process line;
       read_line ();
in read_line ();;

read_lines some_file print_endline;;
1
Pinecone

Scanfの「文字列表示」と幅ゼロの文字を使用してファイルから行を読み取る別のスタイル。それは伝統的な命令型のようなものです。

open Scanf 
open Printf

(* little helper functions *)
let id x = x 
let const x = fun _ -> x
let read_line file = fscanf file "%s@\n" id 
let is_eof file = try fscanf file "%0c" (const false) with End_of_file -> true

let _ = 
  let file = open_in "/path/to/file" in 

  while not (is_eof file) do 
    let s = read_line file in
    (* do something with s *) 
    printf "%s\n" s 
  done;

  close_in file

注意:

  1. read_lineは末尾の\ nを無視するため、ファイルの最後の文字が\ nの場合、最後の空の行を見逃しているように見える可能性があります。
  2. scanfを使用する場合、バッファリングのため、同じチャネルで他の低レベルの読み取り値を混合しないでください。混合すると、奇妙な動作が発生します。
1
Jack Tang

Scanfを使用した再帰的なソリューションは次のとおりです。

let read_all_lines file_name =
  let in_channel = open_in file_name in
  let rec read_recursive lines =
    try
      Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> read_recursive (x :: lines))
    with
      End_of_file ->
        lines in
  let lines = read_recursive [] in
  let _ = close_in_noerr in_channel in
  List.rev (lines);;

使用法:

let all_lines = read_all_lines "input.txt";;

ただし、行ごとにストリーミングすることをお勧めします。

let make_reader file_name =
  let in_channel = open_in file_name in
  let closed = ref false in
  let read_next_line = fun () ->
    if !closed then
      None
    else
      try
        Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x))
      with
        End_of_file ->
          let _ = close_in_noerr in_channel in
          let _ = closed := true in
          None in
  read_next_line;;

使用法:

let read_next = make_reader "input.txt";;
let next_line = read_next ();;

そして、少しアイシングかもしれません:

type reader = {read_next : unit -> string option};;

let make_reader file_name =
  let in_channel = open_in file_name in
  let closed = ref false in
  let read_next_line = fun () ->
    if !closed then
      None
    else
      try
        Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x))
      with
        End_of_file ->
          let _ = close_in_noerr in_channel in
          let _ = closed := true in
          None in
  {read_next = read_next_line};;

使用法:

let r = make_reader "input.txt";;
let next_line = r.read_next ();;

お役に立てれば!

1

Std.input_listどうやら Extlib が必要です。これをシステムにインストールする必要があります(libextlib-ocamlおよびlibextlib-ocaml-dev Debianシステム上)。

0
a3nm