strsearch.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:10k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: strsearch.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:40:38  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.17
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: strsearch.cpp,v 1000.3 2004/06/01 19:40:38 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Author:  Mati Shomrat
  35. *
  36. * File Description:
  37. *   String search utilities.
  38. *
  39. *   Currently there are two search utilities:
  40. *   1. An implementation of the Boyer-Moore algorithm.
  41. *   2. A finite state automaton.
  42. *
  43. */
  44. #include <ncbi_pch.hpp>
  45. #include <util/strsearch.hpp>
  46. #include <algorithm>
  47. #include <vector>
  48. #include <ctype.h>
  49. NCBI_USING_NAMESPACE_STD;
  50. BEGIN_NCBI_SCOPE
  51. //==============================================================================
  52. //                            CBoyerMooreMatcher
  53. //==============================================================================
  54. // Public:
  55. // =======
  56. CBoyerMooreMatcher::CBoyerMooreMatcher(const string& pattern, 
  57.                                        NStr::ECase   case_sensitive,
  58.                                        unsigned int  whole_word)
  59. : m_Pattern(pattern), 
  60.   m_PatLen(pattern.length()), 
  61.   m_CaseSensitive(case_sensitive), 
  62.   m_WholeWord(whole_word),
  63.   m_LastOccurrence(sm_AlphabetSize),
  64.   m_WordDelimiters(sm_AlphabetSize)
  65. {
  66.     x_InitPattern();
  67.     // Init the word deimiting alphabet
  68.     if (m_WholeWord) {
  69.         for (int i = 0; i < sm_AlphabetSize; ++i) {
  70.             m_WordDelimiters[i] = (isspace(i) != 0);
  71.         }
  72.     }
  73. }
  74. CBoyerMooreMatcher::CBoyerMooreMatcher(const string& pattern,
  75.                                        const string& word_delimeters,
  76.                                        NStr::ECase   case_sensitive,
  77.                                        bool          invert_delimiters)
  78. : m_Pattern(pattern), 
  79.   m_PatLen(pattern.length()), 
  80.   m_CaseSensitive(case_sensitive), 
  81.   m_WholeWord(true),
  82.   m_LastOccurrence(sm_AlphabetSize),
  83.   m_WordDelimiters(sm_AlphabetSize)
  84. {
  85.     x_InitPattern();
  86.     SetWordDelimiters(word_delimeters, invert_delimiters);
  87. }
  88. void CBoyerMooreMatcher::SetWordDelimiters(const string& word_delimeters,
  89.                                            bool          invert_delimiters)
  90. {
  91.     m_WholeWord = eWholeWordMatch;
  92.     string word_d = word_delimeters;
  93.     if (m_CaseSensitive == NStr::eNocase) {
  94.         NStr::ToUpper(word_d);
  95.     }
  96.     // Init the word delimiting alphabet
  97.     for (int i = 0; i < sm_AlphabetSize; ++i) {
  98.         char ch = m_CaseSensitive ? i : toupper(i);
  99.         string::size_type n = word_d.find_first_of(ch);
  100.         m_WordDelimiters[i] = (!invert_delimiters) == (n != string::npos);
  101.     }
  102. }
  103. void CBoyerMooreMatcher::AddDelimiters(const string& word_delimeters)
  104. {
  105.     if (m_WholeWord == 0) {
  106.         m_WholeWord = eWholeWordMatch;
  107.     }
  108.     string word_d = word_delimeters;
  109.     if (m_CaseSensitive == NStr::eNocase) {
  110.         NStr::ToUpper(word_d);
  111.     }
  112.     for (int i = 0; i < sm_AlphabetSize; ++i) {
  113.         char ch = m_CaseSensitive ? i : toupper(i);
  114.         string::size_type n = word_d.find_first_of(ch);
  115.         if (n != NPOS) {
  116.             m_WordDelimiters[i] = true;
  117.         }
  118.     }
  119. }
  120. void CBoyerMooreMatcher::AddDelimiters(char ch)
  121. {
  122.     if (m_WholeWord == 0) {
  123.         m_WholeWord = eWholeWordMatch;
  124.     }
  125.     m_WordDelimiters[ch] = true;
  126.     if (m_CaseSensitive == NStr::eNocase) {
  127.         ch = toupper(ch);
  128.     }
  129.     
  130.     m_WordDelimiters[ch] = true;
  131. }
  132. void CBoyerMooreMatcher::InitCommonDelimiters()
  133. {
  134.     if (m_WholeWord == 0) {
  135.         m_WholeWord = eWholeWordMatch;
  136.     }
  137.     for (int i = 0; i < sm_AlphabetSize; ++i) {
  138.         char ch = m_CaseSensitive ? i : toupper(i);
  139.         if ((ch >= 'A' && ch <= 'Z') ||
  140.             (ch >= '0' && ch <= '9') ||
  141.             (ch == '_')){
  142.         } else {
  143.             m_WordDelimiters[i] = true;
  144.         }
  145.     }
  146. }
  147. void CBoyerMooreMatcher::x_InitPattern(void)
  148. {
  149.     if ( m_CaseSensitive == NStr::eNocase) {
  150.         NStr::ToUpper(m_Pattern);
  151.     }
  152.     
  153.     // For each character in the alpahbet compute its last occurrence in 
  154.     // the pattern.
  155.     
  156.     // Initilalize vector
  157.     size_t size = m_LastOccurrence.size();
  158.     for ( size_t i = 0;  i < size;  ++i ) {
  159.         m_LastOccurrence[i] = m_PatLen;
  160.     }
  161.     
  162.     // compute right-most occurrence
  163.     for ( int j = 0;  j < (int)m_PatLen - 1;  ++j ) {
  164.         /* int lo = */
  165. m_LastOccurrence[(int)m_Pattern[j]] = m_PatLen - j - 1;
  166.    }
  167. }
  168. SIZE_TYPE CBoyerMooreMatcher::Search(const char*  text, 
  169.                                      SIZE_TYPE shift,
  170.                                      SIZE_TYPE text_len) const
  171. {
  172.     // Implementation note.
  173.     // Case sensitivity check has been taken out of loop. 
  174.     // Code size for performance optimization. (We generally choose speed).
  175.     // (Anatoliy)
  176.     if (m_CaseSensitive == NStr::eCase) {
  177.         while (shift + m_PatLen <= text_len) {
  178.             int j = (int)m_PatLen - 1;
  179.             for(char text_char = text[shift + j];
  180.                 j >= 0 && m_Pattern[j]==(text_char=text[shift + j]);
  181.                 --j) {}
  182.             if ( (j == -1)  &&  IsWholeWord(text, shift, text_len) ) {
  183.                 return  shift;
  184.             } else {
  185.                 shift += (unsigned int)m_LastOccurrence[text[shift + j]];
  186.             }
  187.         }
  188.     } else { // case insensitive NStr::eNocase
  189.         while (shift + m_PatLen <= text_len) {
  190.             int j = (int)m_PatLen - 1;
  191.             for(char text_char = toupper(text[shift + j]);
  192.                 j >= 0 && m_Pattern[j]==(text_char=toupper(text[shift + j]));
  193.                 --j) {}
  194.             if ( (j == -1)  &&  IsWholeWord(text, shift, text_len) ) {
  195.                 return  shift;
  196.             } else {
  197.                 shift += 
  198.                     (unsigned int)m_LastOccurrence[toupper(text[shift + j])];
  199.             }
  200.         }
  201.     }
  202.     return (SIZE_TYPE)-1;
  203. }
  204. // Private:
  205. // ========
  206. // Constants
  207. const int CBoyerMooreMatcher::sm_AlphabetSize = 256;     // assuming ASCII
  208. // Member Functions
  209. bool CBoyerMooreMatcher::IsWholeWord(const char*  text, 
  210.                                      SIZE_TYPE    pos,
  211.                                      SIZE_TYPE    text_len) const
  212. {
  213.     SIZE_TYPE left, right;
  214.     left = right = 1;
  215.     // Words at the beginning and end of text are also considered "whole"
  216.     // check on the left  
  217.     if (m_WholeWord & ePrefixMatch) {
  218.         left = (pos == 0) ||
  219.                ((pos > 0) && m_WordDelimiters[text[pos - 1]]);
  220.     }
  221.     // check on the right
  222.     if (m_WholeWord & eSuffixMatch) {
  223.         pos += (unsigned int)m_PatLen;
  224.         right = (pos == text_len) || 
  225.                 ((pos < text_len) && m_WordDelimiters[text[pos]]);
  226.     }
  227.     return (left && right);
  228. }
  229. END_NCBI_SCOPE
  230. /*
  231. * ===========================================================================
  232. *
  233. * $Log: strsearch.cpp,v $
  234. * Revision 1000.3  2004/06/01 19:40:38  gouriano
  235. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.17
  236. *
  237. * Revision 1.17  2004/05/27 13:40:58  kuznets
  238. * Fixed warnings (GCC 3.4)
  239. *
  240. * Revision 1.16  2004/05/17 21:06:02  gorelenk
  241. * Added include of PCH ncbi_pch.hpp
  242. *
  243. * Revision 1.15  2004/04/01 14:14:02  lavr
  244. * Spell "occurred", "occurrence", and "occurring"
  245. *
  246. * Revision 1.14  2004/03/11 17:02:53  kuznets
  247. * Fixed misspelling in comments
  248. *
  249. * Revision 1.13  2004/03/11 16:56:33  kuznets
  250. * Minor reformatting
  251. *
  252. * Revision 1.12  2004/03/11 16:54:48  kuznets
  253. * CBoyerMooreMatcher::Search fixed incorrect bad-character shift in case
  254. * insensitive search...
  255. *
  256. * Revision 1.11  2004/03/05 15:46:02  kuznets
  257. * fixed crash on 64-bit (sun)
  258. *
  259. * Revision 1.10  2004/03/04 18:25:20  ucko
  260. * Fix compilation errors in previous revision.
  261. *
  262. * Revision 1.9  2004/03/04 17:37:48  kuznets
  263. * CBoyerMooreMatcher added functions to work with different word delimiters
  264. *
  265. * Revision 1.8  2004/03/03 17:56:02  kuznets
  266. * Code cleane up (CBoyerMooreMatcher) to use enums instead of bools,
  267. * better coverage or different types of whole word matchers
  268. *
  269. * Revision 1.7  2004/03/03 14:37:14  kuznets
  270. * bug fix: CBoyerMooreMatcher::IsWholeWord added case when
  271. * the tested token is at the very beggining or end of the text.
  272. *
  273. * Revision 1.6  2004/03/02 20:00:45  kuznets
  274. * Changes in CBoyerMooreMatcher:
  275. *   - added work with memory areas
  276. *   - alternative word delimiters
  277. *   - performance optimizations
  278. *
  279. * Revision 1.5  2003/11/07 17:16:23  ivanov
  280. * Fixed  warnings on 64-bit Workshop compiler
  281. *
  282. * Revision 1.4  2003/02/04 20:16:15  shomrat
  283. * Change signed to unsigned to eliminate compilation warning
  284. *
  285. * Revision 1.3  2002/11/05 23:01:13  shomrat
  286. * Coding style changes
  287. *
  288. * Revision 1.2  2002/11/03 21:59:14  kans
  289. * BoyerMoore takes caseSensitive, wholeWord parameters (MS)
  290. *
  291. * Revision 1.1  2002/10/29 16:33:11  kans
  292. * initial checkin - Boyer-Moore string search and templated text search finite state machine (MS)
  293. *
  294. *
  295. * ===========================================================================
  296. */