Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

Ada Programming/Algorithms/Knuth-Morris-Pratt pattern matcher

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

Algorithms/pattern_match_knuth_morris_pratt_test.adb pattern_match_knuth_morris_pratt_test.adb an implementation for fixed strings Written by Wikibob, 2004, from notes on the Knuth_Morris_Pratt pattern match algorithm adapted to fixed strings of characters. It is in the public domain. If you are using GNAT, use gnatmake to compile and link this program. To use the pattern match functions in your own software extract the inner package's specification and body into separate files. This program is self-contained and demonstrates a particular implementation of the Knuth_Morris_Pratt algorithm applied to fixed strings, with the following restrictions: * the search pattern is limited to a maximum of 256 characters * the caller must first call the function Pre_Compute on a pattern to obtain a context variable containing the pre-computed pattern. There is no limit to the number of contexts. * the caller must handle the exception Pattern_Error that will be raised if function Find_Location was unable to find the pattern in the given string. Suggested improvements to the inner package are: * add type Result_T is record Location : Index; Found : Boolean; end record; and use it instead of raising Pattern_Error. * produce a version that dispenses with the Context and has Find_Location perform the Pre_process internally. References: http://ww0.java3.datastructures.net/handouts/PatternMatching.pdf procedure Pattern_Match_Knuth_Morris_Pratt_Fixed_Test is You may extract this spec into file pattern_match.ads package Pattern_Match is Max_Pattern_Length : constant Positive := 256; type Context is private; function Pre_Compute (Pattern : in String) return Context; precomputes the table of skips for the Pattern. function Find_Location (Of_Context : in Context; In_Text : in String) return Positive; Pattern_Error : exception; alternative is return Natural and use 0 to mean not found. private subtype Pattern_Length_T is Positive range 1..Max_Pattern_Length; type Failure_Function_T is array (Pattern_Length_T) of Positive; subtype Slided_Pattern_T is String (1 .. Max_Pattern_Length); type Context is record Failure_Function : Failure_Function_T; M_Pattern : Slided_Pattern_T; Pattern_Length : Positive; end record; end Pattern_Match; Variables and data for testing. IFPLID_Context : Pattern_Match.Context; SRC_Context : Pattern_Match.Context; Text_Test1 : constant String := "IMCHG DLH5877 -BEGIN ADDR -IFPLID AT05428113 -SRC FPL -RFL F330"; Text_Test2 : constant String := "IMCHG DLH5877 EDDKCLHD -BEGIN ADDR -FAC CFMUTACT AA05428113 FPL -STAR WLD5M -SRC "; IFPLID_Pos : Positive; IFPLID_Pos_2 : Positive := 1; SRC_Pos : Positive; SRC_Pos_2 : Positive; You may extract this spec into file pattern_match.adb package body Pattern_Match is function Pre_Compute (Pattern : in String) return Context is I, J : Positive; Pattern_Context : Context; begin if Pattern = "" then raise Pattern_Error; end if; Pattern_Context.M_Pattern (1..Pattern'Length) := Pattern; Pattern_Context.Pattern_Length := Pattern'Length; Pattern_Context.Failure_Function (1) := 1; I := 2; J := 1; while I <= Pattern_Context.Pattern_Length loop if Pattern (I) = Pattern (J) then we have matched J + 1 chars. Pattern_Context.Failure_Function (I) := J + 1; I := I + 1; J := J + 1; elsif J > 1 then use failure function to shift Pattern J := Pattern_Context.Failure_Function (J - 1); else Pattern_Context.Failure_Function (I) := 1; I := I + 1; end if; end loop; return Pattern_Context; end Pre_Compute; function Find_Location (Of_Context : in Context; In_Text : in String) return Positive is subtype Slided_Text_T is String (1 .. In_Text'Length); Slided_Text : constant Slided_Text_T := Slided_Text_T (In_Text); I, J : Positive; begin I := 1; J := 1; while I <= Slided_Text'Last loop if Slided_Text (I) = Of_Context.M_Pattern (J) then if J = Of_Context.Pattern_Length then return I - J + 1; else I := I + 1; J := J + 1; end if; elsif J > 1 then J := Of_Context.Failure_Function (J - 1); else I := I + 1; end if; end loop; raise Pattern_Error; Or change function to return Natural and return 0. end Find_Location; end Pattern_Match; You may extract the rest of this file into file pattern_match_test.adb and modify accordingly. procedure Check_Pattern_Found (Pattern : in String; At_Location : in Positive; In_Text : in String) is subtype Slided_Text_T is String (1 .. Pattern'Length); Slided_Pattern : constant Slided_Text_T := Slided_Text_T (Pattern); begin if At_Location > In_Text'Last or else At_Location + Pattern'Length - 1 > In_Text'Last or else Slided_Text_T (In_Text (At_Location .. At_Location + Pattern'Length - 1)) /= Slided_Pattern then We expected Find_Location to return the location of the pattern, as it did not there is a program error. raise Program_Error; end if; end Check_Pattern_Found; begin IFPLID_Context := Pattern_Match.Pre_Compute ("-IFPLID "); SRC_Context := Pattern_Match.Pre_Compute ("-SRC "); Expect_Pattern_Found: begin IFPLID_Pos := Pattern_Match.Find_Location (Of_Context => IFPLID_Context, In_Text => Text_Test1); exception when Pattern_Match.Pattern_Error => We expected Find_Location to find the pattern, but it did not so there is a program error. raise Program_Error; end Expect_Pattern_Found; Check_Pattern_Found (Pattern => "-IFPLID ", At_Location => IFPLID_Pos, In_Text => Text_Test1); Expect_Pattern_Not_Found: begin IFPLID_Pos_2 := Pattern_Match.Find_Location (Of_Context => IFPLID_Context, In_Text => Text_Test2); We expected Find_Location to NOT find the pattern, but it did so there is a program error. raise Program_Error; exception when Pattern_Match.Pattern_Error => We expected Find_Location to NOT find the pattern, and it did not so there is no error. null; end Expect_Pattern_Not_Found; if IFPLID_Pos_2 /= 1 then We expected Find_Location to NOT return a result, so there is a program error. raise Program_Error; end if; Expect_Second_Pattern_Found: begin SRC_Pos := Pattern_Match.Find_Location (Of_Context => SRC_Context, In_Text => Text_Test1); exception when Pattern_Match.Pattern_Error => We expected Find_Location to find the pattern, but it did not so there is a program error. raise Program_Error; end Expect_Second_Pattern_Found; Check_Pattern_Found (Pattern => "-SRC ", At_Location => SRC_Pos, In_Text => Text_Test1); Expect_Second_Pattern_Found_At_End: begin SRC_Pos_2 := Pattern_Match.Find_Location (Of_Context => SRC_Context, In_Text => Text_Test2); exception when Pattern_Match.Pattern_Error => We expected Find_Location to find the pattern, but it did not so there is a program error. raise Program_Error; end Expect_Second_Pattern_Found_At_End; Check_Pattern_Found (Pattern => "-SRC ", At_Location => SRC_Pos_2, In_Text => Text_Test2); end Pattern_Match_Knuth_Morris_Pratt_Fixed_Test;