Как читать строки из текстового файла в OCaml? - PullRequest
17 голосов
/ 25 апреля 2011

Это то, что я имею до сих пор.Разве это не все, что тебе нужно?Я получаю сообщение об ошибке «Ошибка: Unbound module Std»

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

Ответы [ 7 ]

22 голосов
/ 25 апреля 2011

Если у вас не установлена ​​ 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

... что в значительной степени то, что у вас есть.

Если у вас есть библиотека с батареями , вы можете прочитать файл в Enum.t и выполнить итерацию по нему следующим образом:

let filelines = File.lines_of filename in
Enum.iter ( fun line -> (*Do something with line here*) ) filelines
16 голосов
/ 04 мая 2014

Если у вас установлена ​​библиотека OCaml Core, то это просто:

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

Если у вас установлено corebuild, вы можете просто скомпилировать свой код:

corebuild filename.byte

, если ваш код находится в файле с именем filename.ml.

Если у вас нет OCaml Core, или вы не хотите его устанавливать, или какая-то другая реализация стандартной библиотеки, то, конечно, вы можете реализовать его с помощью стандартной библиотеки OCaml ванили. Существует функция input_line, определенная в модуле Pervasives, которая автоматически открывается во всех программах 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.

1 голос
/ 23 сентября 2015

Это читает строки файла и печатает каждую из них:

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
1 голос
/ 04 мая 2014

Другой стиль для чтения строк из файла с использованием 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 голос
/ 10 ноября 2012

Вот рекурсивное решение с использованием 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 ();;

Надеюсь, это поможет!

0 голосов
/ 25 мая 2017

Вот простое рекурсивное решение, которое не накапливает строки и не использует внешние библиотеки, но позволяет вам прочитать строку, обработать ее с помощью функции, рекурсивно прочитать следующую до завершения, а затем выйти чисто.Функция выхода закрывает открытый дескриптор файла и сообщает об успехе вызывающей программе.

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;;
0 голосов
/ 25 апреля 2011

Std.input_list очевидно требует Extlib , который вы должны установить в своей системе (libextlib-ocaml и libextlib-ocaml-dev в системах Debian).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...