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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: strsearch.hpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:39:02  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.19
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef UTIL___STRSEARCH__HPP
  10. #define UTIL___STRSEARCH__HPP
  11. /*  $Id: strsearch.hpp,v 1000.2 2004/06/01 19:39:02 gouriano Exp $
  12. * ===========================================================================
  13. *
  14. *                            PUBLIC DOMAIN NOTICE
  15. *               National Center for Biotechnology Information
  16. *
  17. *  This software/database is a "United States Government Work" under the
  18. *  terms of the United States Copyright Act.  It was written as part of
  19. *  the author's official duties as a United States Government employee and
  20. *  thus cannot be copyrighted.  This software/database is freely available
  21. *  to the public for use. The National Library of Medicine and the U.S.
  22. *  Government have not placed any restriction on its use or reproduction.
  23. *
  24. *  Although all reasonable efforts have been taken to ensure the accuracy
  25. *  and reliability of the software and data, the NLM and the U.S.
  26. *  Government do not and cannot warrant the performance or results that
  27. *  may be obtained by using this software or data. The NLM and the U.S.
  28. *  Government disclaim all warranties, express or implied, including
  29. *  warranties of performance, merchantability or fitness for any particular
  30. *  purpose.
  31. *
  32. *  Please cite the author in any work or product based on this material.
  33. *
  34. * ===========================================================================
  35. *
  36. * Author:  Mati Shomrat
  37. *          Anatoliy Kuznetsov
  38. *
  39. * File Description:
  40. *   String search utilities.
  41. *
  42. */
  43. /// @file strsearch.hpp
  44. /// String search utilities.
  45. ///
  46. ///   Currently there are two search utilities:
  47. /// 1. An implementation of the Boyer-Moore algorithm.
  48. /// 2. A finite state automata.
  49. #include <corelib/ncbistd.hpp>
  50. #include <corelib/ncbistr.hpp>
  51. #include <string>
  52. #include <vector>
  53. /** @addtogroup StringSearch
  54.  *
  55.  * @{
  56.  */
  57. BEGIN_NCBI_SCOPE
  58. //============================================================================//
  59. //                            CBoyerMooreMatcher                               //
  60. //============================================================================//
  61. /// This implemetation uses the Boyer-Moore alg. in order to search a single
  62. /// pattern over varying texts.
  63. class NCBI_XUTIL_EXPORT CBoyerMooreMatcher 
  64. {
  65. public:
  66.     enum EWordMatch
  67.     {
  68.         eSubstrMatch = 0,
  69.         ePrefixMatch = (1 << 0),
  70.         eSuffixMatch = (1 << 1),
  71.         eWholeWordMatch = (ePrefixMatch | eSuffixMatch)
  72.     };
  73. public:
  74.     /// Initialize a matcher with the pattern to be matched.
  75.     ///
  76.     /// @param pattern
  77.     ///    Pattern to be matched
  78.     /// @param case_sensitive
  79.     ///    should the search be case sensitive (false by default).
  80.     /// @param whole_word 
  81.     ///    a match is found ony if the pattern was found to 
  82.     ///    be between delimiting characters (whitespaces)
  83.     CBoyerMooreMatcher(const string& pattern,        
  84.                        NStr::ECase   case_sensitive = NStr::eNocase,
  85.                        unsigned int  whole_word = eSubstrMatch);
  86.     
  87.     /// Initialize a matcher with the pattern to be matched.
  88.     ///
  89.     /// @param pattern
  90.     ///    Pattern to be matched
  91.     /// @param word_delimeters 
  92.     ///    a match is found ony if the pattern was found to 
  93.     ///    be between delimiting characters like whitespaces
  94.     ///    and punctuation marks
  95.     /// @param case_sensitive
  96.     ///    should the search be case sensitive (false by default).
  97.     /// @param invert_delimiters
  98.     ///    when TRUE means all characters NOT belonging to
  99.     ///    word_delimeters are to be used
  100.     CBoyerMooreMatcher(const string& pattern,
  101.                        const string& word_delimeters,
  102.                        NStr::ECase   case_sensitive = NStr::eNocase,
  103.                        bool          invert_delimiters = false);
  104.     /// Set word delimiting characters
  105.     ///
  106.     /// @param word_delimeters 
  107.     ///    string of characters used as word delimiters
  108.     /// @param invert_delimiters
  109.     ///    when TRUE means all characters NOT belonging to
  110.     ///    word_delimeters are to be used
  111.     void SetWordDelimiters(const string& word_delimeters,
  112.                            bool          invert_delimiters = false);
  113.     /// Add new word delimiters
  114.     ///
  115.     /// @param word_delimeters 
  116.     ///    string of characters used as word delimiters
  117.     ///
  118.     void AddDelimiters(const string& word_delimeters);
  119.     /// Add new word delimiter charracter
  120.     ///
  121.     /// @param word_delimeters 
  122.     ///    string of characters used as word delimiters
  123.     ///
  124.     void AddDelimiters(char ch);
  125.     /// Init delimiters most common for the English language,
  126.     /// (whitespaces, punctuations, etc)
  127.     void InitCommonDelimiters();
  128.     
  129.     /// Set word matching mode
  130.     ///
  131.     /// @param whole_word 
  132.     ///    word matching mode. Can be OR combination of EWordMatch values
  133.     void SetWordMatching(unsigned int whole_word = eWholeWordMatch)
  134.     {
  135.         m_WholeWord = whole_word;
  136.     }
  137.     /// Search for the pattern over text starting at position pos.
  138.     ///
  139.     /// @param text
  140.     ///    Text to search in.
  141.     /// @param pos
  142.     ///    Position shift in text
  143.     /// @return 
  144.     ///    the position at which the pattern was found, -1 otherwise.
  145.     size_t Search(const string& text, size_t pos = 0) const
  146.     {
  147.         return Search(text.c_str(), pos, text.length());
  148.     }
  149.     /// Search for the pattern over text starting at position pos.
  150.     ///
  151.     /// @param text
  152.     ///    Text memory taken as NON ASCIIZ string.
  153.     /// @param pos 
  154.     ///    String offset position from the start
  155.     /// @param text_len
  156.     ///    Length of text
  157.     /// @return 
  158.     ///    the position at which the pattern was found, -1 otherwise.
  159.     SIZE_TYPE Search(const char*  text, 
  160.                      SIZE_TYPE pos,
  161.                      SIZE_TYPE text_len) const;
  162.     
  163. private:
  164.     // Constants
  165.     static const int sm_AlphabetSize;
  166.     
  167.     // Member Functions:
  168.     
  169.     /// Check if the pattern at position pos in the text lies on a
  170.     /// whole word boundry.
  171.     bool IsWholeWord(const char*   text,
  172.                      SIZE_TYPE     pos,
  173.                      SIZE_TYPE     text_len) const;
  174.     void x_InitPattern(void);
  175. private:    
  176.     string                  m_Pattern;  
  177.     SIZE_TYPE               m_PatLen;
  178.     NStr::ECase             m_CaseSensitive;
  179.     unsigned int            m_WholeWord;
  180.     vector<size_t>          m_LastOccurrence;
  181.     vector<unsigned char>   m_WordDelimiters;
  182.     
  183. };
  184. //============================================================================//
  185. //                          Finite State Automata                             //
  186. //============================================================================//
  187. template <typename MatchType>
  188. class CTextFsm
  189. {
  190. public:
  191.     // Constants (done as an enum to avoid link errors on Darwin)
  192.     enum ESpecialStates {
  193.         eFailState = -1
  194.     };
  195.     
  196.     // Constructors and Destructors:
  197.     CTextFsm(bool case_sensitive = false);
  198.     ~CTextFsm(void);
  199.     
  200.     // Add a word to the Fsm. Store a match for later retreival.
  201.     void AddWord(const string& word, const MatchType& match);
  202.     
  203.     // Prime the FSM.
  204.     // After finishing adding all the words to the FSM it needs to be 
  205.     // primed to enable usage.
  206.     bool IsPrimed(void) const { return m_Primed; }
  207.     void Prime(void);
  208.     
  209.     // Retreive the FSM's initial state.
  210.     int GetInitialState(void) const { return 0; }
  211.     
  212.     // Get the next state, based on the currect state and a transition
  213.     // character.
  214.     int GetNextState(int state, char letter) const;
  215.     
  216.     // Are there any matches stored in state?
  217.     bool IsMatchFound(int state) const;
  218.     
  219.     // Retrieve the stored matches in state.
  220.     const vector<MatchType>& GetMatches(int state) const;
  221.     
  222. private:
  223.     // Internal representation of states.
  224.     class CState
  225.     {
  226.     public:
  227.         // Ad-hoc definitions
  228.         typedef map<char, int> TMapCharInt;
  229.         
  230.         // Constructors and Destructors
  231.         CState(void) : m_OnFailure(0) {}
  232.         ~CState(void) {};
  233.         
  234.         // Add a transition to the table.
  235.         void AddTransition(char letter, int to) { m_Transitions[letter] = to; }
  236.         
  237.         // Retreive the transition state, give the transition character.
  238.         int GetNextState(char letter) const {
  239.     TMapCharInt::const_iterator it = m_Transitions.find(letter);
  240.     return it != m_Transitions.end() ?  it->second : eFailState;
  241.         }
  242.         
  243.         
  244.         // Are there any matches stored in this state?
  245.         bool IsMatchFound(void) const { return !m_Matches.empty(); }
  246.         
  247.         // Retreive the stored matches
  248.         vector<MatchType>& GetMatches(void) { return m_Matches; }
  249.         const vector<MatchType>& GetMatches(void) const { return m_Matches; }
  250.         
  251.         // Store a match.
  252.         void AddMatch(const MatchType& match) { m_Matches.push_back(match); }
  253.         
  254.         const TMapCharInt& GetTransitions(void) const { return m_Transitions; };
  255.         
  256.         // Getter and Setter for failure transition.
  257.         void SetOnFailure(int state) { m_OnFailure = state; }
  258.         int GetOnFailure(void) const { return m_OnFailure; }
  259.         
  260.     private:
  261.         
  262.         // Member Variables:
  263.         TMapCharInt         m_Transitions;   // Transition table
  264.         vector<MatchType>   m_Matches;       // Stored matches
  265.         int                 m_OnFailure;     // Transition state in failure.
  266.         
  267.     };  // end of class CState
  268.     
  269.     // Private Methods:
  270.     CState *GetState(int state);
  271.     int GetNextState(const CState& from, char letter) const;
  272.     
  273.     // Compute the transition to be performed on failure.
  274.     void ComputeFail(void);
  275.     void FindFail(int state, int new_state, char ch);
  276.     void QueueAdd(vector<int>& in_queue, int qbeg, int val);
  277.     
  278.     // Member Variables
  279.     bool                m_Primed;
  280.     vector< CState >    m_States;
  281.     bool                m_CaseSensitive;
  282.     
  283. };  // end of class CTextFsm
  284. // Convenience class when the MatchType is of string type (most cases)
  285. class NCBI_XUTIL_EXPORT CTextFsa : public CTextFsm<string>
  286. {
  287. public:
  288.     CTextFsa(bool case_sensitive = false) :
  289.         CTextFsm<string>(case_sensitive) 
  290.     {}
  291.     void AddWord(const string& word) {
  292.         CTextFsm<string>::AddWord(word, word);
  293.     }
  294. };
  295. //============================================================================//
  296. //                   Finite State Automata Implementation                     //
  297. //============================================================================//
  298. // Public:
  299. // =======
  300. template <typename MatchType>
  301. CTextFsm<MatchType>::CTextFsm(bool case_sensitive) :
  302. m_Primed(false), m_CaseSensitive(case_sensitive)
  303. {
  304.     CState initial;
  305.     m_States.push_back(initial);
  306. }
  307. template <typename MatchType>
  308. void CTextFsm<MatchType>::AddWord(const string& word, const MatchType& match) 
  309. {
  310.     string temp = word;
  311.     if ( !m_CaseSensitive ) {
  312.         NStr::ToUpper(temp);
  313.     }
  314.     int next, i, 
  315.         state = 0,
  316.         word_len = temp.length();
  317.     
  318.     // try to overlay beginning of word onto existing table 
  319.     for ( i = 0;  i < word_len;  ++i ) {
  320.         next = m_States[state].GetNextState(word[i]);
  321.         if ( next == eFailState ) break;
  322.         state = next;
  323.     }
  324.     
  325.     // now create new states for remaining characters in word 
  326.     for ( ;  i < word_len;  ++ i ) {
  327.         CState new_state;
  328.         
  329.         m_States.push_back(new_state);
  330.         m_States[state].AddTransition(temp[i], m_States.size() - 1);
  331.         state = m_States[state].GetNextState(temp[i]);
  332.     }
  333.     
  334.     // add match information 
  335.     m_States[state].AddMatch(match);
  336. }
  337. template <typename MatchType>
  338. void CTextFsm<MatchType>::Prime(void)
  339. {
  340.     if ( m_Primed ) return;
  341.     
  342.     ComputeFail();
  343.     
  344.     m_Primed = true;
  345. }
  346. template <typename MatchType>
  347. typename CTextFsm<MatchType>::CState *CTextFsm<MatchType>::GetState(int state) 
  348. {
  349.     if ( (state < 0) || (state > m_States.size()) ) {
  350.         return 0;
  351.     }
  352.     return &(m_States[state]);
  353. }
  354. template <typename MatchType>
  355. int CTextFsm<MatchType>::GetNextState(const CState& from, char letter) const {
  356.     char ch = m_CaseSensitive ? letter : toupper(letter);
  357.     return from.GetNextState(ch);
  358. }
  359. template <typename MatchType>
  360. int CTextFsm<MatchType>::GetNextState(int state, char letter) const
  361. {
  362.     if ( state < 0 || size_t(state) >= m_States.size() ) {
  363.         return eFailState;
  364.     }
  365.     
  366.     int next;
  367.     int initial = GetInitialState();
  368.     while ( (next = GetNextState(m_States[state], letter)) == eFailState ) {
  369.         if ( state == initial ) {
  370.             next = initial;
  371.             break;
  372.         }
  373.         state = m_States[state].GetOnFailure();
  374.     }
  375.     
  376.     return next;
  377. }
  378. template <typename MatchType>
  379. void CTextFsm<MatchType>::QueueAdd(vector<int>& in_queue, int qbeg, int val)
  380. {
  381.     int  q;
  382.     
  383.     q = in_queue [qbeg];
  384.     if (q == 0) {
  385.         in_queue [qbeg] = val;
  386.     } else {
  387.         for ( ;  in_queue [q] != 0;  q = in_queue [q]) continue;
  388.         in_queue [q] = val;
  389.     }
  390.     in_queue [val] = 0;
  391. }
  392. template <typename MatchType>
  393. void CTextFsm<MatchType>::ComputeFail(void) 
  394. {
  395.     int qbeg, r, s, state;
  396.     vector<int> state_queue(m_States.size());
  397.     
  398.     qbeg = 0;
  399.     state_queue [0] = 0;
  400.     
  401.     // queue up states reached directly from state 0 (depth 1) 
  402.     
  403.     ITERATE ( typename CState::TMapCharInt,
  404.               it, 
  405.               m_States[GetInitialState()].GetTransitions() ) {
  406.         s = it->second;
  407.         m_States[s].SetOnFailure(0);
  408.         QueueAdd(state_queue, qbeg, s);
  409.     }
  410.     
  411.     while (state_queue [qbeg] != 0) {
  412.         r = state_queue [qbeg];
  413.         qbeg = r;
  414.         
  415.         // depth 1 states beget depth 2 states, etc. 
  416.         
  417.         ITERATE ( typename CState::TMapCharInt, it,
  418.                   m_States[r].GetTransitions() ) {
  419.             s = it->second;
  420.             QueueAdd(state_queue, qbeg, s);
  421.             
  422.             //   State   Substring   Transitions   Failure
  423.             //     2       st          a ->   3       6
  424.             //     3       sta         l ->   4
  425.             //     6       t           a ->   7       0
  426.             //     7       ta          p ->   8
  427.             //
  428.             //   For example, r = 2 (st), if 'a' would go to s = 3 (sta).
  429.             //   From previous computation, 2 (st) fails to 6 (t).
  430.             //   Thus, check state 6 (t) for any transitions using 'a'.
  431.             //   Since 6 (t) 'a' -> 7 (ta), therefore set fail [3] -> 7.
  432.             
  433.             state = m_States[r].GetOnFailure();
  434.             FindFail(state, s, it->first);
  435.         }
  436.     }
  437. }
  438. template <typename MatchType>
  439. void CTextFsm<MatchType>::FindFail(int state, int new_state, char ch)
  440. {
  441.     int        next;
  442.     
  443.     // traverse existing failure path 
  444.     
  445.     while ( (next = GetNextState(state, ch)) == eFailState) {
  446.         if ( state == 0 ) {
  447.             next = 0; break;
  448.         }
  449.         state = m_States[state].GetOnFailure();
  450.     }
  451.     
  452.     // add new failure state 
  453.     
  454.     m_States[new_state].SetOnFailure(next);
  455.     
  456.     // add matches of substring at new state 
  457.     
  458.     copy( m_States[next].GetMatches().begin(), 
  459.         m_States[next].GetMatches().end(),
  460.         back_inserter(m_States[new_state].GetMatches()) );
  461. }
  462. template <typename MatchType>
  463. const vector<MatchType>& CTextFsm<MatchType>::GetMatches(int state) const {
  464.     return m_States[state].GetMatches();
  465. }
  466. template <typename MatchType>
  467. bool CTextFsm<MatchType>::IsMatchFound(int state) const
  468. {
  469.     return m_States[state].IsMatchFound();
  470. }
  471. template <typename MatchType>
  472. CTextFsm<MatchType>::~CTextFsm(void) 
  473. {}
  474. END_NCBI_SCOPE
  475. /* @} */
  476. /*
  477. * ===========================================================================
  478. *
  479. * $Log: strsearch.hpp,v $
  480. * Revision 1000.2  2004/06/01 19:39:02  gouriano
  481. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.19
  482. *
  483. * Revision 1.19  2004/05/27 13:41:16  kuznets
  484. * Fixed warnings (GCC 3.4)
  485. *
  486. * Revision 1.18  2004/04/26 14:52:34  ucko
  487. * Add "typename" as needed to accommodate GCC 3.4's stricter treatment of
  488. * templates.
  489. *
  490. * Revision 1.17  2004/04/01 14:14:01  lavr
  491. * Spell "occurred", "occurrence", and "occurring"
  492. *
  493. * Revision 1.16  2004/03/05 15:45:23  kuznets
  494. * fixed compilation warnings on 64-bit (Sun)
  495. *
  496. * Revision 1.15  2004/03/04 17:37:38  kuznets
  497. * CBoyerMooreMatcher added functions to work with different word delimiters
  498. *
  499. * Revision 1.14  2004/03/03 17:55:47  kuznets
  500. * Code cleane up (CBoyerMooreMatcher) to use enums instead of bools,
  501. * better coverage or different types of whole word matchers
  502. *
  503. * Revision 1.13  2004/03/02 19:59:57  kuznets
  504. * Changes in CBoyerMooreMatcher:
  505. *   - added work with memory areas
  506. *   - alternative word delimiters
  507. *
  508. * Revision 1.12  2003/05/23 13:33:55  dicuccio
  509. * Changed local variable name from 'queue' to avoid clash with queue<>
  510. *
  511. * Revision 1.11  2003/04/17 17:50:36  siyan
  512. * Added doxygen support
  513. *
  514. * Revision 1.10  2003/03/10 17:56:34  kuznets
  515. * iterate->ITERATE
  516. *
  517. * Revision 1.9  2003/02/04 20:15:16  shomrat
  518. * Change int to unsigned
  519. *
  520. * Revision 1.8  2003/01/22 20:03:56  vasilche
  521. * Removed compiler warning.
  522. *
  523. * Revision 1.7  2002/12/19 14:51:00  dicuccio
  524. * Added export specifier for Win32 DLL builds.
  525. *
  526. * Revision 1.6  2002/11/13 19:12:23  shomrat
  527. * Add prime checking
  528. *
  529. * Revision 1.5  2002/11/12 15:38:56  ucko
  530. * Since sm_FailState was constant anyway, made it into a (singleton)
  531. * enum element so it won't end up as an undefined symbol on Darwin.
  532. *
  533. * Revision 1.4  2002/11/06 15:08:03  ucko
  534. * Remove extraneous CState:: that caused trouble with MIPSpro.
  535. *
  536. * Revision 1.3  2002/11/05 22:58:57  shomrat
  537. * Coding style changes; Case sensetivity option added to finite state automata; Bug fix in GetNextState
  538. *
  539. * Revision 1.2  2002/11/03 21:58:49  kans
  540. * BoyerMoore takes caseSensitive, wholeWord parameters (MS)
  541. *
  542. * Revision 1.1  2002/10/29 16:32:52  kans
  543. * initial checkin - Boyer-Moore string search and templated text search finite state machine (MS)
  544. *
  545. *
  546. * ===========================================================================
  547. */
  548. #endif   // UTIL___STRSEARCH__HPP