2016-04-17 6 views
2

Я хочу прочитать строку из файла, инициализировать массив из этой строки, а затем отобразить целые числа. Почему не читаются пять целых чисел в строке? Я хочу, чтобы получить выход 1 2 3 4 5, у меня есть 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";; 

Мой файл только: 1 2 3 4 5

+0

Почему не читаются пять целых чисел в строке? Я хочу получить результат 1 2 3 4 5, у меня есть 11111 – vanmarcke

+0

Это часть 'sscanf s"% d "(fun a -> a)': вы всегда сканируете ту же строку 's' с самого начала. 'sscanf' не изменяет вашу строку. –

+0

Что я могу сделать, чтобы получить все целые числа из строки? Существует int_of_string, но это попытается преобразовать всю строку в число. Также есть, но это только даст мне char не целые числа. – vanmarcke

ответ

3

Вы можете попробовать следующий подход. Разделите строку в список подстрок, представляющих числа. This answer описывает один из способов сделать это. Затем используйте полученную функцию в функции print_ints.

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" 

При компиляции, пройти str.cma или str.cmxa в качестве аргумента (см this answer подробную информацию о компиляции):

$ ocamlc str.cma print_ints.ml 

Другой альтернативой было бы использовать в Scanf.bscanf функцию - this question, содержит пример (использование с осторожностью).

Функция Scanf.sscanf не может быть особенно подходящей для этой задачи. Отрывок из OCaml manual:

зсапЕ объект не предназначен для тяжелых лексического и синтаксического анализа. Если окажется не достаточно выразительной для ваших потребностей, несколько альтернативы существует: регулярные выражения (модуль Str), поток парсеры, ocamllex генерируемых лексеров, ocamlyacc сгенерированных парсеров

Там есть хоть способ разбор строки Интса используя Scanf.sscanf (который я бы не рекомендовал):

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 _ -> [] 

хитрость здесь, чтобы представить строку ввода s как часть, которая собирается быть проанализирован в целое (%d), а остальные строки используя формат диапазона: %[0-9-+ ]", который будет соответствовать остальной части строки, содержащей только десятичное копание его 0-9, знаки - и + и пробелы .

+0

Это решает проблему. Ocaml очень эффективен с такими вещами, как карта, но для сканирования кажется ограниченным использование внешних вещей. С помощью sscanf я могу это сделать? Похоже, я всегда должен был знать, сколько ints для формата. – vanmarcke

+0

'Str' - стандартный модуль (не внешний), просто компиляция немного сложнее. Да, вы должны исправить свою строку формата (я обновил ответ, чтобы отразить это). –

+0

Вам может понравиться этот [учебник по потокам] (https://ocaml.org/learn/tutorials/streams.html). Вы можете использовать потоки здесь 'let int_stream_of_string s = Stream.of_list (List.map int_of_string (Str.split (Str.regexp" + ") s))' для обработки ваших строк по частям. –

Смежные вопросы