How to make Scanf.sscanf do exact match?

I am trying to have an exact match using Scanf.sscanf below, i,e. I want f to only execute when i match "hello" exactly. But it doesn’t seem to work. Any ideas?

let print_hello i = 
    let f = Printf.printf "hello\n" in 
    Scanf.sscanf i "hello" f
;;
utop # print_hello "hello";;
hello
- : unit = ()
utop # print_hello "hello_world";;
hello
- : unit = ()
utop # print_hello "world";;
hello
Exception:
Stdlib.Scanf.Scan_failure
  "scanf: bad input at char number 0: looking for 'h', found 'w'".

Is there a way to specify sscanf to have an exact match?

1 Like

f isn’t a function; it has type unit. So when you call print_hello, it first unconditionally evaluates Printf.printf "hello\n" - which is what’s causing the printing - and then binds the unit result to f.

I’m not very familiar with Scanf.sscanf, but playing around with it a bit I think it does have the behavior you want. E.g.:

# let f s = Scanf.sscanf s "hello\n" ();;
val f : string -> unit = <fun>
# f "hello\n";;
- : unit = ()
# f "hello";;
Exception: End_of_file.

Thanks for the input.

It seems I need to use %! to match end of input in my fmt. Here is the correct version,

let print_hello i = 
    let f = Printf.printf "hello\n" in 
    Scanf.sscanf i "hello%!" f
;;
1 Like

I don’t think this function is doing what you expect. As written it’s exactly equivalent to:

let print_hello i = 
    Printf.printf "hello\n";
    Scanf.sscanf i "hello%!" ()
;;

Indeed, I actually just wanted the %! part which I discovered after re-reading the Scanf manual again. So the complete version is below,

# let print_hello i = 
  Scanf.sscanf i "hello%!" (fun () -> Printf.printf "hello\n")
;;
val print_hello : string -> unit -> unit = <fun>

# print_hello "hello" ();;
hello 
- : unit = ()

# print_hello "he" ();;
Exception: End_of_file.

# print_hello "hello world" ();;
Exception:
Stdlib.Scanf.Scan_failure
 "scanf: bad input at char number 5: end of input not found".
1 Like