vanmarcke
vanmarcke

Reputation: 133

reading integers from a string

I want to read a line from a file, initialize an array from that line and then display the integers. Why is is not reading the five integers in the line? I want to get output 1 2 3 4 5, i have 1 1 1 1 1

open Array;;
open Scanf;;

let print_ints file_name = 
  let file = open_in file_name in
  let s = input_line(file) in
  let n = ref 5 in
  let arr = Array.init !n (fun i -> if i < !n then sscanf s "%d" (fun a -> a) else 0) in
  let i = ref 0 in 
  while !i < !n do
    print_int (Array.get arr !i);
    print_string " ";
    i := !i + 1;
  done;;

print_ints "string_ints.txt";;

My file is just: 1 2 3 4 5

Upvotes: 2

Views: 2176

Answers (1)

Anton Trunov
Anton Trunov

Reputation: 15414

You might want to try the following approach. Split your string into a list of substrings representing numbers. This answer describes one way of doing so. Then use the resulting function in your print_ints function.

let ints_of_string s = 
  List.map int_of_string (Str.split (Str.regexp " +") s)

let print_ints file_name = 
  let file = open_in file_name in
  let s = input_line file in
  let ints = ints_of_string s in
  List.iter (fun i -> print_int i; print_char ' ') ints;
  close_in file

let _ = print_ints "string_ints.txt"

When compiling, pass str.cma or str.cmxa as an argument (see this answer for details on compilation):

$ ocamlc str.cma print_ints.ml

Another alternative would be using the Scanf.bscanf function -- this question, contains an example (use with caution).

The Scanf.sscanf function may not be particularly suitable for this task. An excerpt from the OCaml manual:

the scanf facility is not intended for heavy duty lexical analysis and parsing. If it appears not expressive enough for your needs, several alternative exists: regular expressions (module Str), stream parsers, ocamllex-generated lexers, ocamlyacc-generated parsers

There is though a way to parse a string of ints using Scanf.sscanf (which I wouldn't recommend):

let rec int_list_of_string s =
  try
    Scanf.sscanf s 
                 "%d %[0-9-+ ]" 
                 (fun n rest_str -> n :: int_list_of_string rest_str)
  with
    | End_of_file | Scanf.Scan_failure _ -> []

The trick here is to represent the input string s as a part which is going to be parsed into a an integer (%d) and the rest of the string using the range format: %[0-9-+ ]", which will match the rest of the string, containing only decimal digits 0-9, the - and + signs, and whitespace .

Upvotes: 3

Related Questions