home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ocl150a.zip / OCL / Source / OFuzzSearch.cpp < prev    next >
C/C++ Source or Header  |  1997-04-05  |  6KB  |  214 lines

  1. // OCL - OS/2 Class Library
  2. // (c) Cubus 1995
  3. // All Rights Reserved
  4. // OFuzzSearch.cpp
  5.  
  6.  
  7. /*
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Neither the name Cubus nor the name Team OCL may be used to
  14.  *    endorse or promote products derived from this software
  15.  *    without specific prior written permission.
  16.  * 3. See OCL.INF for a detailed copyright notice.
  17.  *
  18.  *              THIS SOFTWARE IS PROVIDED ``AS IS'' AND
  19.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE.
  29.  */
  30.  
  31.  
  32. // $Header:$
  33.  
  34. #define __OCL_SOURCE__
  35.  
  36. #define OINCL_OSTRING
  37. #define OINCL_BASE
  38.  
  39. #include <ocl.hpp>
  40. #include <OFuzzSearch.hpp>
  41. #include <ctype.h>
  42.  
  43.  
  44. #if defined(__EMX__)
  45.   template class OList<OFuzzMatch>;
  46.   template class OConstIterator<OFuzzMatch>;
  47. #endif
  48.  
  49. OFuzzSearch::OFuzzSearch(PCSZ  FileName,
  50.                          PCSZ  SearchString,
  51.                          float Threshold,
  52.                          ULONG MaxParLen)
  53.   : file(FileName),
  54.     parLen(MaxParLen),
  55.     threshold(Threshold),
  56.     searchFor(SearchString)
  57. {} 
  58.  
  59.  
  60. OFuzzSearch::~OFuzzSearch()
  61. {}
  62.  
  63.  
  64. PSZ OFuzzSearch::isOfType() const
  65. {
  66.  return("OFuzzSearch");
  67. }
  68.  
  69. void OFuzzSearch::startSearch()
  70. {
  71.  fuzzyMatching();
  72. }
  73.  
  74.  
  75. void OFuzzSearch::printMatches()
  76. {
  77.  matches.allElementsDo(printer);
  78. }
  79.  
  80.  
  81. void OFuzzSearch::fuzzyMatching()
  82. {
  83.  OString TextPara(parLen);
  84.  OString TextBuffer(parLen);
  85.  INT     TextLen,
  86.          SearchStrLen,
  87.          NGram1Len,
  88.          NGram2Len,
  89.          MatchCount1,
  90.          MatchCount2,
  91.          MaxMatch1,
  92.          MaxMatch2;
  93.  float   Similarity;
  94.  FILE    *InFile;
  95.  
  96.  
  97.  TextPara.getText()[0] = ' ';
  98.  
  99.  if((InFile = fopen(file.getText(),"r")) == NULL)
  100.    throw OVioException(OCL::error(OCL_OFUZZ_OFILE),
  101.                        0, OException::recoverable);
  102.  
  103.  SearchStrLen = prepareString(searchFor.getText(), searchFor.getText());
  104.  NGram1Len = 3;
  105.  NGram2Len = (SearchStrLen < 7) ? 2 : 5;
  106.  
  107.  fseek(InFile, 0L, SEEK_SET);
  108.  while (fgets(TextBuffer.getText(), parLen - 1, InFile))
  109.   {
  110.    TextLen = prepareString(&TextPara.getText()[1], TextBuffer.getText());
  111.    if (TextLen < parLen - 2)
  112.      {
  113.       MatchCount1 = NGramMatch(TextPara.getText(), searchFor.getText(),
  114.                                SearchStrLen, NGram1Len, &MaxMatch1);
  115.       MatchCount2 = NGramMatch(TextPara.getText(), searchFor.getText(),
  116.                                SearchStrLen, NGram2Len, &MaxMatch2);
  117.  
  118.       Similarity = 100.0
  119.                    * (float)(MatchCount1 + MatchCount2)
  120.                    / (float)(MaxMatch1 + MaxMatch2);
  121.  
  122.       if(Similarity >= threshold)
  123.        {
  124.         OFuzzMatch *matchElement = new OFuzzMatch;
  125.  
  126.         matchElement->text << TextBuffer;
  127.         matchElement->similarity = Similarity; 
  128.         matches << matchElement;
  129.        }
  130.      }
  131.    else
  132.       throw OVioException(OCL::error(OCL_OFUZZ_PARLEN),
  133.                           0, OException::recoverable);
  134.   }
  135. }
  136.  
  137.  
  138. LONG OFuzzSearch::prepareString(PSZ  ConvStr,
  139.                                 PSZ  OriginStr)
  140. {
  141.  PSZ  TmpPtr;
  142.  
  143.  for (TmpPtr = ConvStr; *OriginStr; TmpPtr++, OriginStr++)
  144.     {
  145.       *TmpPtr = tolower(*OriginStr);
  146.       if (*OriginStr < '0')
  147.         *TmpPtr = ' ';
  148.       else
  149.         switch((unsigned char)*TmpPtr)
  150.           {
  151.             case 196: *TmpPtr = 228; break; /* ANSI-Umlaute  */
  152.             case 214: *TmpPtr = 246; break;
  153.             case 220: *TmpPtr = 252; break;
  154.             case 142: *TmpPtr = 132; break; /* ASCII-Umlaute */
  155.             case 153: *TmpPtr = 148; break;
  156.             case 154: *TmpPtr = 129; break;
  157.             case ':': *TmpPtr = ' '; break;
  158.             case ';': *TmpPtr = ' '; break;
  159.             case '<': *TmpPtr = ' '; break;
  160.             case '>': *TmpPtr = ' '; break;
  161.             case '=': *TmpPtr = ' '; break;
  162.             case '?': *TmpPtr = ' '; break;
  163.             case '[': *TmpPtr = ' '; break;
  164.             case ']': *TmpPtr = ' '; break;
  165.           }
  166.     }
  167.   *TmpPtr = '\0';
  168.   return (TmpPtr - ConvStr);
  169. }
  170.  
  171.  
  172. INT OFuzzSearch::NGramMatch(PSZ  TextPara,
  173.                             PSZ  SearchStr,
  174.                             INT  SearchStrLen,
  175.                             INT  NGramLen,
  176.                             INT* MaxMatch)
  177. {
  178.  CHAR  NGram[8];
  179.  INT   NGramCount;
  180.  INT   i, Count;
  181.  
  182.  NGram[NGramLen] = '\0';
  183.  NGramCount = SearchStrLen - NGramLen + 1;
  184.  
  185.  for(i = 0, Count = 0, *MaxMatch = 0; i < NGramCount; i++)
  186.    {
  187.     memcpy(NGram, &SearchStr[i], NGramLen);
  188.       
  189.     if (NGram[NGramLen - 2] == ' ' && NGram[0] != ' ')
  190.       i += NGramLen - 3;
  191.     else
  192.       {
  193.        *MaxMatch  += NGramLen;
  194.        if(strstr(TextPara, NGram)) Count++;
  195.       }
  196.    }
  197.  
  198.  return Count * NGramLen;
  199. }
  200.  
  201.  
  202.  
  203. void OFuzzSearch::OFuzzMatchPrint::applyToElement(const OFuzzMatch *elem) const
  204. {
  205.  cout << elem->similarity
  206.       << "% in:"
  207.       << endl
  208.       << (PSZ) elem->text.getText()
  209.       << endl
  210.       << endl;
  211. }
  212.  
  213. // end of source
  214.