File: kmp.ml

package info (click to toggle)
ocaml-doc 3.09-1
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 10,428 kB
  • ctags: 4,963
  • sloc: ml: 9,244; makefile: 2,413; ansic: 122; sh: 49; asm: 17
file content (71 lines) | stat: -rw-r--r-- 2,447 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*               Pierre Weis, projet Cristal, INRIA Rocquencourt       *)
(*                                                                     *)
(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  only by permission.                                                *)
(*                                                                     *)
(***********************************************************************)

(* Find the first occurrence of string [p] (the so-called ``pattern'')
   into the string [s].
   Elaborated algorithm.
   Knuth-Morris-Pratt algorithm following Sedgewick's book "Algorithms".
   The Caml code was proved correct in the Coq Proof Assistant.
   Based on a mail to the Caml list by Jean-Christophe FILLIATRE. *)

let init_next p =
  let m = String.length p in
  let next = Array.create m 0 in
  let i = ref 1 and j = ref 0 in
  while !i < m - 1 do
    if p.[!i] = p.[!j] then begin incr i; incr j; next.(!i) <- !j end else
    if !j = 0 then begin incr i; next.(!i) <- 0 end else j := next.(!j)
  done;
  next;;

let kmp p =
  let next = init_next p
  and m = String.length p in
  function s ->
    let n = String.length s
    and i = ref 0
    and j = ref 0 in
    while !j < m && !i < n do
      if s.[!i] = p.[!j] then begin incr i; incr j end else
      if !j = 0 then incr i else j := next.(!j)
    done;
    if !j >= m then !i - m else raise Not_found;;

let find_pat p s =
  try
    let i = kmp p s in
    print_string "Match found at character ";
    print_int i;
    print_newline ();
    exit 0
  with Not_found ->
    print_string "Pattern ";
    print_string p;
    print_string " does not match string ";
    print_string s;
    print_newline ();
    exit 2;;

let usage () =
  print_string
   "Usage: kmp <pat> <str>\n\
    returns the index of the first occurrence of <pat> in string <str>\n";
  exit 2;;

let main () =
  let args = Sys.argv in
  if Array.length args < 2 then usage () else
   let p = Sys.argv.(1)
   and s = Sys.argv.(2) in
  find_pat p s;;

if !Sys.interactive then () else main ();;