Reputation: 303
I have an input file in following format :
q0;q1
a;b
(q0,x);(q1;x)
I want to have three lists as follows:
a = ["q0";"q1"];
b = ["a";"b"];
c = [("q0","x");("q1","y")];
Here is my code :
let buf = Queue.create ();;
let catfile filename =
let rec print_all_lines in_chan =
Queue.add (input_line in_chan) buf;
print_all_lines in_chan
in
let in_file = open_in filename in
try
print_all_lines in_file
with End_of_file -> close_in in_file;;
catfile "test.txt";;
let rec pvt_rec_split skipf rv str c i limit =
if (List.length rv < (limit - 1)) && (i < String.length str) then (
if String.contains_from str i c then
let o = String.index_from str i c in
pvt_rec_split skipf
(rv @ [ String.sub str i (o - i)])
str c
(skipf str c o)
limit;
else
rv @ [ String.sub str i ((String.length str) - i) ]
) else (
if i < String.length str then
rv @ [ String.sub str i ((String.length str) - i) ]
else
rv
);;
let split s c limit =
let rec pvt_skip_char s c i =
if (i >= String.length s ) then (
String.length s
) else (
if ((String.get s i) == c) then (
pvt_skip_char s c (i +1)
) else (
i
)
)
in
pvt_rec_split pvt_skip_char [] s c 0 limit ;;
let a = split (Queue.take buf) ';' 100;;
let b = split (Queue.take buf) ';' 100;;
let c = split (Queue.take buf) ';' 100;;
Basically split function splits the string with delimiter and returns a list.
So, I am able to generate list a and b properly.
But in case of List c, I get a type string list. Actually I want a list with type ('string*'string).
How do I do that?
Upvotes: 2
Views: 3344
Reputation: 6922
File contents (notice comma-separations inside brackets)
q0;q1
a;b
(q0,x);(q1,x)
Ocaml code
let split_str separator s =
let list = ref [] in
let start = ref 0 in
let () = try
while true do
let index = String.index_from s !start separator in
list := (String.sub s !start (index - !start)) :: !list;
start := index + 1
done
with Not_found -> list := (String.sub s !start ((String.length s) - !start)) :: !list
in List.rev !list;;
let maybe_input_line stdin =
try Some (input_line stdin) with
End_of_file -> None;;
let input_lines stdin =
let rec input lines =
match maybe_input_line stdin with
Some line -> input (line :: lines)
| None -> List.rev lines
in
input [];;
let rec parse_list_line delim line =
if (String.length line) > 0 then
let parts = split_str delim line in
parse_tokens parts
else
[]
and parse_tokens tokens =
let rec inner_parse_tokens buffer = function
[] -> List.rev buffer
| h :: t ->
let parsed = parse_line h in
inner_parse_tokens (parsed :: buffer) t
in
inner_parse_tokens [] tokens
and parse_line str =
if (String.length str) > 1 then
if str.[0] = '(' && str.[(String.length str) - 1] = ')' then
let substr = String.sub str 1 ((String.length str) - 2) in
split_str ',' substr
else
str :: []
else
str :: []
and parse_lines lines =
let rec inner_parse chunks = function
[] -> List.rev chunks
| head :: rest ->
let parsed = parse_list_line ';' head in
inner_parse (parsed :: chunks) rest
in
inner_parse [] lines;;
let file_channel = open_in("read_file2");;
let all_lines = input_lines file_channel;;
let chunks = parse_lines all_lines;;
let () = close_in file_channel;;
And the output
# val file_channel : in_channel = <abstr>
# val all_lines : string list = ["q0;q1"; "a;b"; "(q0,x);(q1,x)"]
# val chunks : string list list list =
[[["q0"]; ["q1"]]; [["a"]; ["b"]]; [["q0"; "x"]; ["q1"; "x"]]]
Please, notice, that in last output we have to use lists for single string items in order to return same type from ocaml functions. If you want, you can write something similar to matlab squeeze function to change [["q0"]; ["q1"]]
to ["q0"; "q1"]
Upvotes: 2