I am currently trying to use ocaml-re. Documentation is sparse. I was wondering how I would, for instance, do the equivalent:
Str.regexp "example \\([A-Za-z]+\\)" using Re.Perl? I think it would help me to naturally get the rest of the documentation on my own. Thank you!
Bonus points if you convert this code from Str to Re.Perl:
let read_filename = "example.ts"
let filename = "example2.ts"
let () =
CCIO.(
let modify_file ~chunks =
let r = Str.regexp "example \\([A-Za-z]+\\)" in
match chunks () with
None -> chunks (* is the same as (fun () -> None) *)
| Some chunks ->
let test_chunks = Str.replace_first r "\\1" chunks in (* compute once *)
(fun () -> Some test_chunks) in
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file ~chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
Don't use Re.Perl, Re's API is much simpler. You can constructor your re with:
let re =
let open Re in
alt [rg 'A' 'Z'; rg 'a' 'z'] (* [A-Za-z] *)
|> rep1a (* [A-Za-z]+ *)
|> group (* ([A-Za-z]+) *)
|> compile
Related
I have some OCaml code:
let (&>) : ('x -> 'y) -> ('y -> 'z) -> ('x -> 'z) =
fun g f x -> x |> g |> f
let soi x = string_of_int x
let sof x = string_of_float x
let fos x = float_of_string x
let ios x = int_of_string x
let clear_int = ios &> soi
let is_int_clear (x: string) =
let targ = clear_int x in
let _ = print_endline x in
let _ = print_endline targ in
x == targ
let ccc = is_int_clear "123"
let scc = if ccc then "succ" else "fail"
let () = print_endline scc
I think "123" should be equal to "123" but output this:
123
123
fail
"123" was not equal "123".
Why and how to fix it?
The fault in your logic lies in using == which tests for physical equality. This is checking that the two strings reside at the same location in memory.
You wanted to use = which tests for structural equality: whether the two values contain the same information.
The change is very simple.
let is_int_clear (x: string) =
let targ = clear_int x in
let _ = print_endline x in
let _ = print_endline targ in
x = targ
can you help me out, i made this program to get an output from some .txt file like this :
john:3:uk
paul:18:us
#load "str.cma"
let f_test = "/home/test.txt" ;;
(*
Recursive Reading function
*)
let read_lines f_test : string list =
if Sys.file_exists (f_test) then
begin
let ic = open_in f_test in
try
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_noerr ic; List.rev acc in
loop []
with e ->
close_in_noerr ic;
[]
end
else
[]
;;
(*Using Records*)
type user =
{
name : string;
age : int;
country : string;
};;
(*
Function to separated info in list
*)
let rec splitinfo ?(sep=":") l = match l with
| [] -> []
| x::xs -> (Str.split (Str.regexp ":") x)::splitinfo xs;;
(*
Function to get users position
*)
let get_user l:user =
let age = int_of_string (List.nth l 1) in
let user_name = List.nth l 0 in
{
name = user_name;
age = age ;
country = List.nth l 2;
};;
(*
Function to check some parameter is valid
*)
let par1 u: int =
if (u.age = 3) then
1
else
0;;
(*
Reporting function
*)
let report_statistics list_users =
let child = ref 0 in
let teenager = ref 0 in
let adult = ref 0 in print_string (" ----- -- Stats -- ----- \n" ) ;
List.iter (
fun user_l -> (
match user_l with
| [] -> print_string("> no user <\n")
| _ ->
let user = get_user user_l in
if (par1 user = 1) then (
print_string (" "^ user.name ^" --> Child \n" ) ;
child := !child + 1;
)
else
print_string (" "^ user.name ^" --> Other \n" );
)
) list_users;
print_string ("------- List ---- ");
print_newline();
print_string ("Child " );
print_int(!child);
print_newline();
print_string ("Teenager ") ;
print_int(!teenager);
print_newline();
print_string ("Adult ");
print_int(!adult);
print_newline();
;;
The program compile but doesn't output any result ...
What am i missing ?
I kept the function to check parameters simple so i can understand it better but can't figure it out why it isn't outputing any result
Can you help me out here ?
Thanks in advance :)
The code as given defines some functions such as read_lines and report_statistics. But there are no calls to these functions.
If there is no other OCaml source involved, this is probably your problem. You need to call the functions.
It is fairly customary to have a "main" function that does the work of an OCaml program, and then (this is key) you have to actually call the main function:
let main () =
(* Call the functions that do the work of the program *)
let () = main ()
I have many times forgotten this last line and then nothing happens when I run the program.
In the ocaml-containers documentation, it gives a great example, how to read in a file, and write the content to a different file here. However, I am trying to see what it would take to modify the text before it is passed from the file being read to file being written.
let read_filename = "example.ts"
let filename = "example2.ts"
let () =
let modify_file ~chunks =
let r = Str.regexp "text \\([A-Za-z]+\\)" in
Str.replace_first r "\\1" chunks in
CCIO.(
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
The issue with this code, is that the compiler complains:
File "component.ml", line 13, characters 39-45:
Error: This expression has type string gen = unit -> string option
but an expression was expected of type string
I am trying to figure out what I am doing wrong, but to no avail. Any help would be more than appreciated. Also, suggestions as to the ideal enterprise software to use in OCaml to modify text in files, is more than appreciated. Thank you.
You have a typing problem
read_chunk ic return a string gen value
from here we learn that is a function that take unit value () and return a string.
let () =
CCIO.(
let modify_file ~chunks =
let r = Str.regexp "example \\([A-Za-z]+\\)" in
match chunks () with
None -> chunks (* is the same as (fun () -> None) *)
| Some chunks ->
let chunks = Str.replace_first r "\\1" chunks in (* compute once *)
(fun () -> Some chunks) in
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file ~chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
EDIT:
explain the error and the change
EDIT 2:
I have modifier modify_file so it return antoher string gen and corrected the syntax error: when you use labeled argument you need to add a tilde when calling it
What is the type of modify_file. I don't see it in the manual.
You should try to add unit value () this way
let new_chunks = modify_file chunks () in and new_chunks will be of type string option
You can pattern match as option type.
EDIT:
I have seen that third parameter has type string gen
You should modify the 16th line this way:
write_gen oc (fun () -> new_chunks)
I have some tests on infinite lazy structures that might run indefinitely if the tested function is not correctly implemented, but I can’t find in the OUnit docs how to set a timeout on tests.
If you're using OUnit2, the following should work:
let tests =
"suite" >::: [OUnitTest.TestCase (
OUnitTest.Short,
(fun _ -> assert_equal 2 (1+1))
);
OUnitTest.TestCase (
OUnitTest.Long,
(fun _ -> assert_equal 4 (2+2))
)]
The type test_length is defined as:
type test_length =
| Immediate
| Short
| Long
| Huge
| Custom_length of float
I don't think that oUnit provides this functionality. I remember having to do this a while back and this is the quick hack I've come up with:
let race seconds ~f =
let ch = Event.new_channel () in
let timeout = Thread.create (fun () ->
Thread.delay seconds;
`Time_out |> Event.send ch |> Event.sync
) () in
let tf = Thread.create (fun () ->
`Result (f ()) |> Event.send ch |> Event.sync) () in
let res = ch |> Event.receive |> Event.sync in
try
Thread.kill timeout;
Thread.kill tf;
res
with _ -> res
let () =
let big_sum () =
let arr = Array.init 1_000_000 (fun x -> x) in
Array.fold_left (+) 0 arr in
match race 0.0001 ~f:big_sum with
| `Time_out -> print_endline "time to upgrade";
| `Result x -> Printf.printf "sum is: %d\n" x
This worked well enough for my use case but I'd definitely would not recommend using this if only because race will not work as you'd expect if ~f does no allocations or calls Thread.yield manually.
I can't wrap my head around where should I put parenthesis to get it working:
let read_lines filename =
let channel = open_in filename in
Std.input_list channel;;
let print_lines filename =
List.map print_string ((^) "\n") (read_lines filename);;
^ This is the closes I've got so far. If my terminology is vague: ((^) "\n") is what I call partial function (well, because it doesn't handle all of its arguments). print_string I call total function because... well, it handles all of its arguments.
Obviously, what I would like to happen is that:
List.map applies first ((^) "\n") to the element of the list.
List.map applies print_string to the result of #1.
How? :)
Maybe you want something like that?
# let ($) f g = fun x -> f(g x);;
val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
# let f = print_string $ (fun s -> s^"\n");;
val f : string -> unit = <fun>
# List.iter f ["a";"b";"c";"d"];;
a
b
c
d
- : unit = ()
# let g = string_of_int $ ((+)1) $ int_of_string;;
val g : string -> string = <fun>
# g "1";;
- : string = "2"
Your code didn't work because missing parenthesis:
List.map print_string ((^) "\n") xs
is parsed as
(List.map print_string ((^) "\n")) xs
when you expected
List.map (print_string ((^) "\n")) xs
A few things: List.map is probably not what you want, since it will produce a list (of unit values) rather than just iterating. ((^) "\n") is probably also not what you want, as it prepends a newline, the "\n" being the first argument. (This is not a section as in Haskell, but a straightforward partial application.)
Here's a reasonable solution that is close to what (I think) you want:
let print_lines filename =
List.iter (fun str -> print_string (str ^ "\n")) (read_lines filename)
But I would rather write
let print_lines filename =
List.iter (Printf.printf "%s\n") (read_lines filename)
Which is both clearer and more efficient.