home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / asm / SIMILF.ZIP / SIMILF.ASM
Encoding:
Assembly Source File  |  1989-06-17  |  16.1 KB  |  314 lines

  1. ;
  2. ;  S I M I L F . A S M
  3. ;  =================
  4. ;  Entered & adapted by J Meeks (& Herb Martin a little); latest
  5. ;  version 05-09-89, 00:13am.
  6. ;
  7. ;  Adapted from Dr. Dobb's Journal, 07-88 issue, pp. 46-51 (text), pp.
  8. ;  68-72 (program listing).
  9. ;
  10. ;  Written by John W. Ratcliff & David E. Metzener, 11-10-87.
  11. ;
  12. ;  Uses the Ratcliff/Obershelp pattern recognition algorithm.
  13. ;
  14. ;  This program provides a new function for Turbo Pascal 5.0 on an
  15. ;  8086-based machine.  The function similf returns a percentage value
  16. ;  corresponding to the degree to which two strings are similar to one
  17. ;  another.  Be certain to convert both strings to uppercase if you
  18. ;  want to have a comparison that is case-insensitive.
  19. ;
  20. ;  NOTE: This routine is for use with Turbo Pascal 5.0 programs.  The
  21. ;  original simil is for use with C programs, and is almost identical
  22. ;  to this one.
  23. ;
  24.          TITLE   SIMILF.ASM
  25. ;
  26.          ASSUME  CS: Code, DS: Data, ES: Data
  27. ;
  28. DATA     SEGMENT
  29. ;
  30. ststr1l  dw      25 dup (?)      ; Lefts for string 1.
  31. ststr1r  dw      25 dup (?)      ; Rights for string 1.
  32. ststr2l  dw      25 dup (?)      ; Lefts for string 2.
  33. ststr2r  dw      25 dup (?)      ; Rights for string 2.
  34. stcknum  dw      ?               ; # elements on stack.
  35. score    dw      ?               ; # chars in common * 2.
  36. total    dw      ?               ; Total # chars in strings 1 & 2.
  37. cl1      dw      ?               ; Left of string 1 found in common.
  38. cr1      dw      ?               ; Right of string 1 found in common.
  39. cl2      dw      ?               ; Left of string 2 found in common.
  40. cr2      dw      ?               ; Right of string 2 found in common.
  41. s2ed     dw      ?               ; End of string 2 used in compare.
  42. ;
  43. DATA     ENDS
  44.          PUBLIC similf
  45. ;
  46. Code    SEGMENT
  47. ;
  48. similf  PROC    NEAR
  49. ;
  50. ;  This routine expects pointers passed to two character strings, null
  51. ;  terminated, that you wish compared.  It returns a percentage value
  52. ;  from 0% to 100% corresponding to how alike the two strings are.
  53. ;
  54. ;  Usage:       Simil (Str1, Str2: string);
  55. ;
  56. ;  The similarity routine is composed of three major components:
  57. ;    compare   Finds the largest group of characters in common between
  58. ;                any two string sections.
  59. ;    pushst    Pushes a string section to be compared onto the stack.
  60. ;    popst     Pops a string section to be examined off the stack.
  61. ;
  62. ;  The similarity routine begins by computing the total length of both
  63. ;  strings passed and placing that value in total.  It then takes the
  64. ;  beginnings and endings of both strings passed and pushes them onto
  65. ;  the stack.  It then falls through into the main line code.
  66.  
  67. ;  The original two strings are immediately popped off the stack and
  68. ;  are passed to the compare routine.  The compare routine finds the
  69. ;  largest group of characters in common between the two strings.
  70.  
  71. ;  The number of characters in common is multiplied by two and added
  72. ;  to the total score.  If there were no characters in common, then
  73. ;  there is nothing to push onto the stack.  If there is exactly one
  74. ;  character to the left in both strings then we needn't push them
  75. ;  onto the stack (we already know they aren't equal from the previous
  76. ;  call to compare). Otherwise the characters on the left are pushed
  77. ;  onto the stack.  These same rules apply to characters to the right
  78. ;  of the substring found in in common.  This process of popping
  79. ;  substrings off the stack, comparing them, and pushing remaining
  80. ;  sections onto the stack is continued until the stack is empty.
  81.  
  82. ;  On return, the total score is divided by the number of characters
  83. ;  in both strings.  This is multiplied by 100 to yield a percentage.
  84. ;  This percentage similarity is returned to the calling procedure.
  85.  
  86.          push    bp                ; Save BP.
  87.          mov     bp, sp            ; Save SP in BP for use in program.
  88.          push    es                ; Save ES.
  89.          mov     ax, ds            ; Copy DS into ES.
  90.          mov     es, ax
  91.          xor     ax, ax            ; Clear AX.
  92.          mov     score, ax         ; Clear score variable.
  93.          mov     stcknum, ax       ; Clear number of stack entries.
  94.          mov     si, [bp+4]        ; Move string 1 begin ptr to SI.
  95.          mov     di, [bp+8]        ; Move string 2 begin ptr to DI.
  96.          cmp     [si], al          ; Is string 1 a null string?
  97.          je      strerr            ; Can't process null strings!
  98.          cmp     [di], al          ; Is string 2 a null string?
  99.          jne     docmp             ; Neither string null; process 'em.
  100. strerr:  jmp     donit             ; Jump to exit routine.
  101. docmp:   push    di                ; Save DI (because of SCAS).
  102.          push    si                ; Save SI (because of SCAS).
  103.          xor     al, al            ; Clr AL to search for string end.
  104.          cld                       ; Clr direction flag to forward.
  105.          mov     cx, -1            ; Repeat correct # times.
  106.          repnz   scasb             ; Scan for delimiter in string 2.
  107.          dec     di
  108.          dec     di                ; Point DI to last char of str 2.
  109.          mov     bp, di            ; Move DI to BP, where should be.
  110.          pop     di                ; Original SI into DI for scasb.
  111.          repnz   scasb             ; Scan for delimiter in string 1.
  112.          not     cx                ; 1's comp of string 1's lentgh.
  113.          sub     cx, 2             ; - 2 zero bytes at end string 1.
  114.          mov     total, cx         ; Sum of strings' lengths in total.
  115.          dec     di
  116.          dec     di                ; Point DI to last char of str 1.
  117.          mov     bx, di            ; Move DI to BX, where should be.
  118.          pop     di                ; Restore original DI.
  119.          call    pushst            ; Push for 1st call to compare.
  120. main:    cmp     stcknum, 0        ; Is there anything on the stack?
  121.          je      done              ; No.  Nothing to compare!
  122.          call    popst             ; Set up regs for a compare call.
  123.          call    compare           ; Do compare for substring set.
  124.          cmp     dx, 0             ; Nothing in common to push.
  125.          je      main              ; Try another set substrings.
  126.          shl     dx, 1             ; Multiply # common chars by 2.
  127.          add     score, dx         ; Add 2 * common chars to total.
  128.          mov     bp, stcknum       ; Get # of entry to be looked at.
  129.          shl     bp, 1             ; Ready AX to access string stk.
  130.          mov     si, [ststr1l+bp]  ; Move l1 into SI (or l1).
  131.          mov     bx, cl1           ; Move cl1 into BX (or r1).
  132.          mov     di, [ststr2l+bp]  ; Move l2 into DI (or l2).
  133.          mov     cx, cl2           ; Move cl2 into CX temporarily.
  134.          mov     ax, [ststr1r+bp]  ; Get old r1 off stack.
  135.          mov     cl1, ax           ; Place in cl1 temporarily.
  136.          mov     ax, [ststr2r+bp]  ; Get old r2 off stack.
  137.          mov     cl2, ax           ; Place in cl2 temporarily.
  138.          mov     bp, cx            ; Move cl2 into BP.
  139.          cmp     bx, si            ; Compare cl1 to l1.
  140.          je      chrght            ; Nothing on left side of string 1.
  141.          cmp     bp, di            ; Compare cl2 to l2.
  142.          je      chrght            ; Nothing on left side of string 2.
  143.          dec     bx                ; Point last part left side str 1.
  144.          dec     bp                ; Point last part left side str 2.
  145.          cmp     bx, si            ; Only one char to compare?
  146.          jne     pushit            ; No.  We need to examine this.
  147.          cmp     bp, di            ; Only one character in both?
  148.          je      chrght            ; Only 1 char; nothing to look at.
  149. pushit:  call    pushst            ; Push left side onto stack.
  150. chrght:  mov     si, cr1           ; Move cr1 into SI (or l1).
  151.          mov     bx, cl1           ; Move r1 into BX (or r1).
  152.          mov     di, cr2           ; Move cr2 into DI (or l2).
  153.          mov     bp, cl2           ; Move r2 into BP (or r2).
  154.          cmp     si, bx            ; Compare cr1 to r1.
  155.          je      main              ; Nothing on right side of str 1.
  156.          cmp     di, bp            ; Compare cr2 to r2.
  157.          je      main              ; Nothing on right side of str 2.
  158.          inc     si                ; Point last part right side str 1.
  159.          inc     di                ; Point last part right side str 2.
  160.          cmp     bx, si            ; Only one character to examine?
  161.          jne     push2             ; No.  Examine it.
  162.          cmp     bp, di            ; Only one character in both?
  163.          je      main              ; Yes.  Get next strs off stack.
  164. push2:   call    pushst            ; Push right side onto stack.
  165.          jmp short  main           ; Do next level of compares.
  166. done:    mov     ax, score         ; Get score into AX for multiply.
  167.          mov     cx, 100           ; Put 100 into CX for multiply.
  168.          mul     cx                ; Multiply score by 100.
  169.          mov     cx, total         ; Get total # chars for divide.
  170.          div     cx                ; Div (score * 100) by # chars.
  171. donit:   pop     es                ; Restore ES to entry value.
  172.          POP     BP                ; Restore BP to entry value.
  173.          ret     8                 ; Return; AX = % similarity.
  174. similf  ENDP
  175. ;
  176. ;
  177. compare  PROC    NEAR
  178. ;
  179. ;  The compare procedure locates the largest matching group of
  180. ;  characters between string 1 and string 2.  The routine assumes
  181. ;  the CPU's direction flag is cleared.
  182. ;
  183. ;  Pass to this routine:
  184. ;    DS:SI   l1 (left side of string 1),
  185. ;    BX      r1 (right side of string 1),
  186. ;    ES:DI   l2 (left side of string 2),
  187. ;    BP      r2 (right side of string 2).
  188. ;  The routine returns:
  189. ;    DX      # characters matching,
  190. ;    cl1     Left side of first matching substring,
  191. ;    cl2     Left side of second matching substring,
  192. ;    cr1     Right side of first matching substring,
  193. ;    cr2     Right side of second matching substring.
  194. ;
  195. ;  The compare routine is composed of two loops, an inner and an
  196. ;  outer. The worst case scenario is that there are absolutely no
  197. ;  characters in common between string 1 and string 2.  In this case
  198. ;  N * M compares are performed.  However, when a substring match
  199. ;  occurs in the inner loop, then the next character to be examined in
  200. ;  string 2 (for this loop) is advanced by the number of characters
  201. ;  found equal. Whenever a new maximum number of characters in common
  202. ;  is found then the ending locations of both the inner and outer
  203. ;  loops are backed off by the difference between the new max chars
  204. ;  value and the old max chars value; i.e., if 5 characters have been
  205. ;  found in common part of the way through the search then we can cut
  206. ;  our search short by 5 characters since there is no chance of
  207. ;  finding better than a 5-character match at that point.  This
  208. ;  technique means that an exact match will require only a single
  209. ;  compare, and combinations of other matches will proceed as
  210. ;  efficiently as possible.
  211. ;
  212. ;  Note that we branch downward for both newmax and newmax2, because
  213. ;  on the 8086 line of processors a branch not taken is much faster
  214. ;  than one that is taken.  Since the not-equal condition is to be
  215. ;  found most often, and we would like the inner loop to execute as
  216. ;  quickly as possible, we branch outside the loop's body on the less
  217. ;  frequent occurence.  When a match and/or a new maxchars is found
  218. ;  then we branch down to these two routines, process the new
  219. ;  conditions, then jump back up into the main line loop code.
  220.          mov     s2ed, bp          ; Store end of string 2.
  221.          xor     dx, dx            ; Initialize maxchars.
  222. forl3:   push    di                ; Save start of string 2.
  223. forl4:   push    di                ; Save start of string 2.
  224.          push    si                ; Save start of string 1.
  225.          mov     cx, s2ed          ; Set up to calc length of str 1.
  226.          sub     cx, di            ; Get (length of string 1) - 1.
  227.          inc     cx                ; Get length of string 1.
  228.          push    cx                ; Save starting length of str 1.
  229.          repz    cmpsb             ; Compare strings.
  230.          jz      equal             ; If equal, skip fixes.
  231.          inc     cx                ; Back up (CMPSB decs even if <>).
  232. equal:   pop     ax                ; Get starting length of string 1.
  233.          sub     ax, cx            ; Get length of common substring.
  234.          jnz     newmax            ; More than zero chars matched.
  235.          pop     si                ; Get back start of string 1.
  236.          pop     di                ; Get back start of string 2.
  237. reent:   inc     di                ; Do next char no matter what.
  238. reent2:  cmp     di, bp            ; Are we done with string 2?
  239.          jle     forl4             ; No.  Do next string compare.
  240.          pop     di                ; Get back start of string 2.
  241.          inc     si                ; Next char in string 1 to scan.
  242.          cmp     si, bx            ; Are we done with string 1?
  243.          jle     forl3             ; No.  Do next string compare.
  244.          ret                       ; Return with maxchars in DX.
  245. ;
  246. newmax:  cmp     ax, dx            ; Greater than maxchars?
  247.          jg      newmx2            ; Yes.  Update new maxchars & ptrs.
  248.          pop     si                ; Get back start of string 1.
  249.          pop     di                ; Get back start of string 2.
  250.          add     di, ax            ; Skip past matching chars.
  251.          jmp short  reent2         ; Re-enter inner loop.
  252. newmx2:  pop     si                ; Get back start of string 1.
  253.          pop     di                ; Get back start of string 2.
  254.          mov     cl1, si           ; Put beginning match of str 1.
  255.          mov     cl2, di           ; Put beginning match of str 2.
  256.          mov     cx, ax            ; Save new maxchars.
  257.          sub     ax, dx            ; Get delta for str end adjustment.
  258.          sub     bx, ax            ; Adjust end of string 1.
  259.          sub     bp, ax            ; Adjust end of string 2.
  260.          mov     dx, cx            ; New maxchars.
  261.          dec     cx                ; Set up advance last match char.
  262.          add     di, cx            ; Advance to last match char str 2.
  263.          mov     cr2, di           ; Put ending of match of string 2.
  264.          add     cx, si            ; Advance to last match char str 1.
  265.          mov     cr1, cx           ; Put ending of match of string 1.
  266.          jmp short  reent          ; Re-enter inner loop.
  267. ;
  268. compare  ENDP
  269. pushst   PROC    NEAR
  270. ;
  271. ;  Pass to this routine:
  272. ;    DS:SI   l1 (left side of string 1),
  273. ;    BX      r1 (right side of string 1),
  274. ;    ES:DI   l2 (left side of string 2),
  275. ;    BP      r2 (right side of string 2).
  276. ;
  277.          mov     cx, bp            ; Save r2.
  278.          mov     bp, stcknum       ; Get # entries on stack.
  279.          shl     bp, 1             ; Multiply by 2 for words.
  280.          mov     [bp+ststr1l], si  ; Put left side string 1 on stack.
  281.          mov     [bp+ststr1r], bx  ; Put right side string 1 on stack.
  282.          mov     [bp+ststr2l], di  ; Put left side string 2 on stack.
  283.          mov     [bp+ststr2r], cx  ; Put right side string 2 on stack.
  284.          inc     stcknum           ; Add 1 to number stack entries.
  285.          mov     bp, cx            ; Restore r2.
  286.          ret                       ; Return.
  287. ;
  288. pushst   ENDP
  289. ;
  290. ;
  291. popst    PROC    NEAR
  292. ;
  293. ;  Pass to this routine:
  294. ;    DS:SI   l1 (left side of string 1),
  295. ;    BX      r1 (right side of string 1),
  296. ;    ES:DI   l2 (left side of string 2),
  297. ;    BP      r2 (right side of string 2).
  298. ;
  299.          dec     stcknum           ; Point to last entry in stack.
  300.          mov     bp, stcknum       ; Get # entries on stack.
  301.          shl     bp, 1             ; * 2 for words.
  302.          mov     si, [bp+ststr1l]  ; Restore left string 1 from stk.
  303.          mov     bx, [bp+ststr1r]  ; Restore right string 1 from stk.
  304.          mov     di, [bp+ststr2l]  ; Restore left string 2 from stk.
  305.          mov     bp, [bp+ststr2r]  ; Restore right string 2 from stk.
  306.          ret                       ; Return.
  307. ;
  308. popst    ENDP
  309. ;
  310. ;
  311. Code     ENDS
  312. ;
  313.          END    ; of file SimilF.Asm.
  314.