mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1391 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1391 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
//+------------------------------------------------------------------+
 | 
						|
//|                                               Regular Expression |
 | 
						|
//|                        Copyright 2016, MetaQuotes Software Corp. |
 | 
						|
//|                                             https://www.mql5.com |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Regular Expression Library from .NET Framework 4.6.1 implemented |
 | 
						|
//| in MetaQuotes Language 5 (MQL5)                                  |
 | 
						|
//| Original sources at https://github.com/Microsoft/referencesource |
 | 
						|
//|                                                                  |
 | 
						|
//| The capabilities of the Regular Expression Library include:      |
 | 
						|
//| - Lazy quantifiers                                               |
 | 
						|
//| - Positive and negative lookbehind                               |
 | 
						|
//| - Conditional evaluation                                         |
 | 
						|
//| - Balancing group definitions                                    |
 | 
						|
//| - Nonbacktracking subexpressions                                 |
 | 
						|
//| - Right-to-left matching                                         |
 | 
						|
//|                                                                  |
 | 
						|
//| If you find any functional differences between Regular Expression|
 | 
						|
//| Library for MQL5 and the original .NET Framework 4.6.1 project,  |
 | 
						|
//| please contact developers of MQL5 on the Forum at www.mql5.com.  |
 | 
						|
//|                                                                  |
 | 
						|
//| You can report bugs found in the computational algorithms of the |
 | 
						|
//| Regular Expression Library from .Net Framework 4.6.1 by notifying|
 | 
						|
//| the project coordinators.                                        |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//|                     The MIT License (MIT)                        |
 | 
						|
//|                                                                  |
 | 
						|
//| Permission is hereby granted, free of charge, to any person      |
 | 
						|
//| obtaining a copy of this software and associated documentation   |
 | 
						|
//| files (the "Software"), to deal in the Software without          |
 | 
						|
//| restriction, including without limitation the rights to use,     |
 | 
						|
//| copy, modify, merge, publish, distribute, sublicense, and/or sell|
 | 
						|
//| copies of the Software, and to permit persons to whom the        |
 | 
						|
//| Software is furnished to do so, subject to the following         |
 | 
						|
//| conditions:                                                      |
 | 
						|
//|                                                                  |
 | 
						|
//| The above copyright notice and this permission notice shall be   |
 | 
						|
//| included in all copies or substantial portions of the Software.  |
 | 
						|
//|                                                                  |
 | 
						|
//| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  |
 | 
						|
//| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES  |
 | 
						|
//| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND         |
 | 
						|
//| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT      |
 | 
						|
//| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,     |
 | 
						|
//| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     |
 | 
						|
//| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR    |
 | 
						|
//| OTHER DEALINGS IN THE SOFTWARE.                                  |
 | 
						|
//|                                                                  |
 | 
						|
//| A copy of the MIT License (MIT) is available at                  |
 | 
						|
//| https://opensource.org/licenses/MIT                              |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class Match;
 | 
						|
class MatchCollection;
 | 
						|
class CachedCodeEntry;
 | 
						|
class ReplacementReference;
 | 
						|
class RunnerReference;
 | 
						|
class RegexRunner;
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Callback class.                                                  |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
typedef string(*MatchEvaluator)(Match*);
 | 
						|
#include <Internal\TimeSpan\TimeSpan.mqh>
 | 
						|
#include <Internal\Generic\LinkedList.mqh>
 | 
						|
#include <Internal\Generic\Dictionary.mqh>
 | 
						|
#include "RegexOptions.mqh"
 | 
						|
#include "RegexCode.mqh"
 | 
						|
#include "RegexTree.mqh"
 | 
						|
#include "RegexParser.mqh"
 | 
						|
#include "RegexReplacement.mqh"
 | 
						|
#include "RegexWriter.mqh"
 | 
						|
#include "RegexMatchCollection.mqh"
 | 
						|
#include "RegexRunner.mqh"
 | 
						|
#include "RegexInterpreter.mqh"
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Purpose: The Regex class represents a single compiled instance of| 
 | 
						|
//| a regular expression.                                            |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Represents an immutable, compiled regular expression. Also       |
 | 
						|
//| contains static methods that allow use of regular expressions    |
 | 
						|
//| without instantiating a Regex explicitly.                        |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class Regex
 | 
						|
  {
 | 
						|
protected:
 | 
						|
   string            m_pattern;
 | 
						|
   RegexOptions      m_roptions;
 | 
						|
private:
 | 
						|
   static const TimeSpan MaximumMatchTimeout;
 | 
						|
public:
 | 
						|
   static const TimeSpan InfiniteMatchTimeout;
 | 
						|
protected:
 | 
						|
   TimeSpan          m_internalMatchTimeout;// timeout for the execution of this regex
 | 
						|
private:
 | 
						|
   static const string DefaultMatchTimeout_ConfigKeyName;
 | 
						|
public:
 | 
						|
   static const TimeSpan FallbackDefaultMatchTimeout;
 | 
						|
   static const TimeSpan DefaultMatchTimeout;
 | 
						|
protected:
 | 
						|
   Dictionary<int,int>*m_caps;        // if captures are sparse, this is the hashtable capnum->index
 | 
						|
   Dictionary<string,int>*m_capnames; // if named captures are used, this maps names->index
 | 
						|
   string            m_capslist[];    // if captures are sparse or named captures are used, this is the sorted list of names
 | 
						|
   int               m_capsize;       // the size of the capture array
 | 
						|
   RegexTree        *m_tree;
 | 
						|
   RunnerReference *m_runnerref;      // cached runner
 | 
						|
   ReplacementReference*m_replref;    // cached parsed replacement pattern
 | 
						|
   RegexCode        *m_code;          // if interpreted, this is the code for RegexIntepreter
 | 
						|
   bool              m_refsInitialized;// Default is false
 | 
						|
   static            LinkedList<CachedCodeEntry*>m_livecode;// the cached of code that are currently loaded
 | 
						|
   static int        m_cacheSize;     // Default is 15
 | 
						|
public:
 | 
						|
   static const int  MaxOptionShift;
 | 
						|
public:
 | 
						|
   //--- Constructors:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Initializes a new instance of the Regex class.                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     Regex() : m_refsInitialized(false)
 | 
						|
     {
 | 
						|
      this.m_internalMatchTimeout=DefaultMatchTimeout;
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Creates and compiles a regular expression object for the         |
 | 
						|
   //| specified regular expression.                                    |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     Regex(const string pattern) : m_refsInitialized(0)
 | 
						|
     {
 | 
						|
      Initialize(pattern,None,DefaultMatchTimeout,false);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Creates and compiles a regular expression object for the         |
 | 
						|
   //| specified regular expression with options that modify the        |
 | 
						|
   //| pattern.                                                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     Regex(const string pattern,RegexOptions options) : m_refsInitialized(0)
 | 
						|
     {
 | 
						|
      Initialize(pattern,options,DefaultMatchTimeout,false);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Initializes a new instance of the Regex class for the specified  |
 | 
						|
   //| regular expression,with options that modify the pattern and a    |
 | 
						|
   //| value that specifies how long a pattern matching method should   |
 | 
						|
   //| attempt a match before it times out.                             |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     Regex(const string pattern,RegexOptions options,const TimeSpan &matchTimeout) : m_refsInitialized(0)
 | 
						|
     {
 | 
						|
      Initialize(pattern,options,matchTimeout,false);
 | 
						|
     }
 | 
						|
   //--- Destructors:     
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Destructor without parameters.                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                    ~Regex()
 | 
						|
     {
 | 
						|
      if(CheckPointer(m_tree)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_tree;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_caps)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_caps;
 | 
						|
        }
 | 
						|
      bool deleteRun=true;
 | 
						|
      bool deleteRepl = true;
 | 
						|
      bool deleteCode = true;
 | 
						|
      for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | 
						|
        {
 | 
						|
         if(CheckPointer(current.Value())==POINTER_DYNAMIC)
 | 
						|
           {
 | 
						|
            if(current.Value().RunnerRef()==m_runnerref)
 | 
						|
              {
 | 
						|
               deleteRun=false;
 | 
						|
              }
 | 
						|
            if(current.Value().ReplRef()==m_replref)
 | 
						|
              {
 | 
						|
               deleteRepl=false;
 | 
						|
              }
 | 
						|
            if(current.Value().Code()==m_code)
 | 
						|
              {
 | 
						|
               deleteCode=false;
 | 
						|
              }
 | 
						|
           }
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_replref)==POINTER_DYNAMIC && deleteRepl)
 | 
						|
        {
 | 
						|
         delete m_replref;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_runnerref)==POINTER_DYNAMIC && deleteRun)
 | 
						|
        {
 | 
						|
         delete m_runnerref;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_code)==POINTER_DYNAMIC && deleteCode)
 | 
						|
        {
 | 
						|
         delete m_code;
 | 
						|
        }
 | 
						|
     }
 | 
						|
private:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| General constructor with parameters.                             |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     Regex(const string pattern,RegexOptions options,const TimeSpan &matchTimeout,const bool useCache) : m_refsInitialized(0)
 | 
						|
     {
 | 
						|
      Initialize(pattern,options,matchTimeout,useCache);
 | 
						|
     }
 | 
						|
   //--- Methods:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Initialize.                                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void Initialize(const string pattern,RegexOptions options,const TimeSpan &matchTimeout,const bool useCache)
 | 
						|
     {
 | 
						|
      RegexTree *tree;
 | 
						|
      CachedCodeEntry *cached=NULL;
 | 
						|
      if(pattern==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'pattern'= Null.");
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      if(options<None || (((int) options)>>MaxOptionShift)!=0)
 | 
						|
        {
 | 
						|
         Print("Argument 'options' out of range.");
 | 
						|
         //--- return 
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      if((options    &ECMAScript)!=0
 | 
						|
         && (options  &~(ECMAScript|IgnoreCase|Multiline
 | 
						|
         #ifdef _DEBUG
 | 
						|
         |Debug
 | 
						|
         #endif
 | 
						|
         ))!=0)
 | 
						|
        {
 | 
						|
         Print("Argument 'options' out of range");
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      ValidateMatchTimeout(matchTimeout);
 | 
						|
      //--- Try to look up this regex in the cache.  We do this regardless of whether useCache is true since there's really no reason not to. 
 | 
						|
      string key=IntegerToString(options)+":"+pattern;
 | 
						|
      cached=LookupCachedAndUpdate(key);
 | 
						|
      this.m_pattern=pattern;
 | 
						|
      this.m_roptions=options;
 | 
						|
      this.m_internalMatchTimeout=matchTimeout;
 | 
						|
      if(cached==NULL)
 | 
						|
        {
 | 
						|
         //--- Parse the input
 | 
						|
         tree=RegexParser::Parse(pattern,(RegexOptions)m_roptions);
 | 
						|
         //--- Extract the relevant information
 | 
						|
         m_capnames=tree.CapNames();
 | 
						|
         tree.GetCapsList(m_capslist);
 | 
						|
         m_code       = RegexWriter::Write(tree);
 | 
						|
         m_caps       = m_code.Caps();
 | 
						|
         m_capsize    = m_code.CapSize();
 | 
						|
         InitializeReferences();
 | 
						|
         m_tree=tree;
 | 
						|
         if(useCache)
 | 
						|
           {
 | 
						|
            cached=CacheCode(key);
 | 
						|
           }
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
         m_caps       = cached.Caps();
 | 
						|
         m_capnames   = cached.CapNames();
 | 
						|
         cached.GetCapList(m_capslist);
 | 
						|
         m_capsize    = cached.CapSize();
 | 
						|
         m_code       = cached.Code();
 | 
						|
         m_runnerref  = cached.RunnerRef();
 | 
						|
         m_replref    = cached.ReplRef();
 | 
						|
         m_refsInitialized=true;
 | 
						|
        }
 | 
						|
     }
 | 
						|
public:
 | 
						|
   //--- Methods:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Pattern.                                                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Pattern()
 | 
						|
     {
 | 
						|
      //--- return pattern
 | 
						|
      return (m_pattern);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Validates that the specified match timeout value is valid.       |
 | 
						|
   //| The valid range is:                                              | 
 | 
						|
   //| TimeSpan::Zero < matchTimeout <= Regex::MaximumMatchTimeout.     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void ValidateMatchTimeout(const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      if(InfiniteMatchTimeout==matchTimeout)
 | 
						|
        {
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      //--- Change this to make sure timeout is not longer then Environment.Ticks cycle length:
 | 
						|
      if(TimeSpan::Zero()<matchTimeout && matchTimeout<=MaximumMatchTimeout)
 | 
						|
        {
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      Print("Argument 'matchTimeout' out of range.");
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Specifies the default RegEx matching timeout value (i.e. the     |
 | 
						|
   //| timeout that will be used if no explicit timeout is specified).  |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static TimeSpan InitDefaultMatchTimeout()
 | 
						|
     {
 | 
						|
      //--- retrun result
 | 
						|
      return (FallbackDefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the runner reference.                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RunnerReference*RunnerReference()
 | 
						|
     {
 | 
						|
      //--- return runner reference
 | 
						|
      return (m_runnerref);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the weak reference.                                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   ReplacementReference*ReplacementReference()
 | 
						|
     {
 | 
						|
      //--- return week reference
 | 
						|
      return (m_replref);
 | 
						|
     };
 | 
						|
   Dictionary<int,int>*Caps()
 | 
						|
     {
 | 
						|
      //---
 | 
						|
      return (m_caps);
 | 
						|
     }
 | 
						|
   Dictionary<string,int>*CapNames()
 | 
						|
     {
 | 
						|
      //--- return 
 | 
						|
      return (m_capnames);
 | 
						|
     }
 | 
						|
   int CapSize()
 | 
						|
     {
 | 
						|
      //--- 
 | 
						|
      return (m_capsize);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns the options passed into the constructor.                 |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RegexOptions Options()
 | 
						|
     {
 | 
						|
      //--- return
 | 
						|
      return (m_roptions);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Escape metacharacters within the string.                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Escape(const string str)
 | 
						|
     {
 | 
						|
      if(StringLen(str)==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'str' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return RegexParser::Escape(str);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Unescape character codes within the string.                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Unescape(const string str)
 | 
						|
     {
 | 
						|
      if(StringLen(str)==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'str' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return RegexParser::Unescape(str);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| CacheCount.                                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static int CacheCount()
 | 
						|
     {
 | 
						|
      //--- return count
 | 
						|
      return (m_livecode.Count());
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| CacheSize.                                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static int CacheSize()
 | 
						|
     {
 | 
						|
      //--- return size
 | 
						|
      return (m_cacheSize);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| CacheSize.                                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void CacheSize(const int value)
 | 
						|
     {
 | 
						|
      if(value<0)
 | 
						|
        {
 | 
						|
         Print("Argument 'value' out of range.");
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      m_cacheSize=value;
 | 
						|
      if(m_livecode.Count()>m_cacheSize)
 | 
						|
        {
 | 
						|
         while(m_livecode.Count()>m_cacheSize)
 | 
						|
           {
 | 
						|
            m_livecode.RemoveLast();
 | 
						|
           }
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| The match timeout used by this Regex instance.                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   TimeSpan MatchTimeout()
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return (m_internalMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| True if the regex is leftward.                                   |
 | 
						|
   //|                                                                  |
 | 
						|
   //| Indicates whether the regular expression matches from right to   |
 | 
						|
   //| left.                                                            |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool RightToLeft()
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return UseOptionR();
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns the regular expression pattern passed into the           |
 | 
						|
   //| constructor.                                                     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string ToString()
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return (m_pattern);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns an array of the group names that are used to capture     |
 | 
						|
   //| groups in the regular expression. Only needed if the regex is not|
 | 
						|
   //| known until runtime, and one wants to extract captured groups.   |
 | 
						|
   //| (Probably unusual, but supplied for completeness.).              |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void GetGroupNames(string &result[])
 | 
						|
     {
 | 
						|
      if(ArraySize(m_capslist)==NULL)
 | 
						|
        {
 | 
						|
         int max=m_capsize;
 | 
						|
         ArrayResize(result,max);
 | 
						|
         for(int i=0; i<max; i++)
 | 
						|
           {
 | 
						|
            result[i]=IntegerToString(i);
 | 
						|
           }
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
         ArrayCopy(result,m_capslist,0,0);
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns an array of the group names that are used to capture     |
 | 
						|
   //| groups in the regular expression. Only needed if the regex is not|
 | 
						|
   //| known until runtime, and one wants to extract captured groups.   |
 | 
						|
   //| (Probably unusual, but supplied for completeness.).              |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void GetGroupNumbers(int &result[])
 | 
						|
     {
 | 
						|
      if(m_caps==NULL)
 | 
						|
        {
 | 
						|
         int max=m_capsize;
 | 
						|
         ArrayResize(result,max);
 | 
						|
         for(int i=0; i<max; i++)
 | 
						|
           {
 | 
						|
            result[i]=i;
 | 
						|
           }
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
         ArrayResize(result,m_caps.Count());
 | 
						|
         DictionaryEnumerator<int,int>*de=m_caps.GetEnumerator();
 | 
						|
         while(de.MoveNext())
 | 
						|
           {
 | 
						|
            result[(int)de.Value()]=(int)de.Key();
 | 
						|
           }
 | 
						|
         delete de;
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Given a group number, maps it to a group name. Note that nubmered|
 | 
						|
   //| groups automatically get a group name that is the decimal string |
 | 
						|
   //| equivalent of its number.                                        |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string GroupNameFromNumber(const int index)
 | 
						|
     {
 | 
						|
      int i=index;
 | 
						|
      if(ArraySize(m_capslist)==NULL)
 | 
						|
        {
 | 
						|
         if(i>=0 && i<m_capsize)
 | 
						|
           {
 | 
						|
            //--- return result
 | 
						|
            return IntegerToString(i);
 | 
						|
           }
 | 
						|
         //--- return result
 | 
						|
         return ("");
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
         if(m_caps!=NULL)
 | 
						|
           {
 | 
						|
            if(!m_caps.ContainsKey(i))
 | 
						|
              {
 | 
						|
               //--- return result
 | 
						|
               return ("");
 | 
						|
              }
 | 
						|
            i=m_caps[i];
 | 
						|
           }
 | 
						|
         if(i>=0 && i<ArraySize(m_capslist))
 | 
						|
           {
 | 
						|
            //--- return result
 | 
						|
            return (m_capslist[i]);
 | 
						|
           }
 | 
						|
         //--- return result
 | 
						|
         return ("");
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Given a group name, maps it to a group number. Note that nubmered|
 | 
						|
   //| groups automatically get a group name that is the decimal string |   
 | 
						|
   //| equivalent of its number.                                        |
 | 
						|
   //|                                                                  |
 | 
						|
   //| Returns -1 if the name is not a recognized group name.           |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   int GroupNumberFromName(const string name)
 | 
						|
     {
 | 
						|
      int result=-1;
 | 
						|
      if(name==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'name' = NNULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- look up name if we have a hashtable of names
 | 
						|
      if(m_capnames!=NULL)
 | 
						|
        {
 | 
						|
         if(!m_capnames.ContainsKey(name))
 | 
						|
           {
 | 
						|
            //--- return result
 | 
						|
            return (-1);
 | 
						|
           }
 | 
						|
         //--- return result
 | 
						|
         return (m_capnames[name]);
 | 
						|
        }
 | 
						|
      //--- convert to an int if it looks like a number
 | 
						|
      result=0;
 | 
						|
      for(int i=0; i<StringLen(name); i++)
 | 
						|
        {
 | 
						|
         ushort ch=StringGetCharacter(name,i);
 | 
						|
         if(ch>'9' || ch<'0')
 | 
						|
           {
 | 
						|
            //--- return result
 | 
						|
            return (-1);
 | 
						|
           }
 | 
						|
         result *= 10;
 | 
						|
         result += (ch - '0');
 | 
						|
        }
 | 
						|
      //--- return int if it's in range
 | 
						|
      if(result>=0 && result<m_capsize)
 | 
						|
        {
 | 
						|
         //--- return result
 | 
						|
         return (result);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return (-1);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the input string for one or more occurrences of the text|
 | 
						|
   //| supplied in the pattern parameter.                               |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static bool IsMatch(const string in,const string pattern)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return IsMatch(in, pattern, None, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more occurrences of the text   |
 | 
						|
   //| supplied in the pattern parameter.                               |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static bool IsMatch(const string in,const string pattern,const RegexOptions options)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return IsMatch(in, pattern, options, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more occurrences of the text   |
 | 
						|
   //| supplied in the pattern parameter.                               |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static bool IsMatch(const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex regex(pattern,options,matchTimeout,true);
 | 
						|
      //--- return result
 | 
						|
      return (regex.IsMatch(in));
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more matches using the         |
 | 
						|
   //| previous pattern, options, and starting position.                |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool IsMatch(const string in)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return IsMatch(in, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more matches using the         |
 | 
						|
   //| previous pattern and options, with a new starting position.      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool IsMatch(const string in,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      Match *run=Run(true,-1,in,0,StringLen(in),startat);
 | 
						|
      bool result=(NULL==run);
 | 
						|
      if(CheckPointer(run)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete run;
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return (result);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more occurrences of the text|
 | 
						|
   //| supplied in the pattern parameter.                               |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static Match *Match(const string in,const string pattern)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Regex::Match(in, pattern, None, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more occurrences of the text|
 | 
						|
   //| supplied in the pattern parameter. Matching is modified with an  |
 | 
						|
   //| option string.                                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static Match *Match(const string in,const string pattern,const RegexOptions options)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Regex::Match(in, pattern, options, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Searches the in string for one or more occurrences of the text|
 | 
						|
   //| supplied in the pattern parameter. Matching is modified with an  |
 | 
						|
   //| option string.                                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static Match *Match(string in,string pattern,RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex *regex=new Regex(pattern,options,matchTimeout,true);
 | 
						|
      //--- return result
 | 
						|
      return (regex.Match(in));
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Matches a regular expression with a string and returns the       |
 | 
						|
   //| precise result as a RegexMatch object.                           |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Match *Match(const string in)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Regex::Match(in, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Matches a regular expression with a string and returns the       |
 | 
						|
   //| precise result as a RegexMatch object.                           |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Match *Match(const string in,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Run(false, -1, in, 0, StringLen(in), startat);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Matches a regular expression with a string and returns the       |
 | 
						|
   //| precise result as a RegexMatch object.                           |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Match *Match(const string in,const int beginning,const int length)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Run(false, -1, in, beginning, length, UseOptionR() ? beginning + length : beginning);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns all the successful matches as if Match was called        |
 | 
						|
   //| iteratively numerous times.                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static MatchCollection *Matches(const string in,const string pattern)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Regex::Matches(in, pattern, None, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns all the successful matches as if Match was called        |
 | 
						|
   //| iteratively numerous times.                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static MatchCollection *Matches(const string in,const string pattern,const RegexOptions options)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Regex::Matches(in, pattern, options, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns all the successful matches as if Match was called        |
 | 
						|
   //| iteratively numerous times.                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static MatchCollection *Matches(const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex *regex=new Regex(pattern,options,matchTimeout,true);
 | 
						|
      //--- return result
 | 
						|
      return (regex.Matches(in));
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns all the successful matches as if Match was called        |
 | 
						|
   //| iteratively numerous times.                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   MatchCollection *Matches(const string in)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Matches(in, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Returns all the successful matches as if Match was called        |
 | 
						|
   //| iteratively numerous times.                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   MatchCollection *Matches(const string in,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return new MatchCollection(GetPointer(this), in, 0, StringLen(in), startat);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the pattern with the "replacement"   |
 | 
						|
   //| pattern, starting at the first character in the in string.       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,const string replacement)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, pattern, replacement, None, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the "replacement" |
 | 
						|
   //| pattern, starting at the first character in the in string.       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,const string replacement,const RegexOptions options)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, pattern, replacement, options, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the "replacement" |
 | 
						|
   //| pattern, starting at the first character in the in string.       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,const string replacement,const RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex *regex = new Regex(pattern,options,matchTimeout,true);
 | 
						|
      string result=regex.Replace(in,replacement);
 | 
						|
      delete regex;
 | 
						|
      //--- return result
 | 
						|
      return (result);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern " with the "replacement"|
 | 
						|
   //| pattern, starting at the first character in the in string, using |
 | 
						|
   //| the previous patten.                                             |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,const string replacement)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, replacement, -1, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the (previously defined) "pattern"   |
 | 
						|
   //| with the "replacement" pattern, starting at the first character  |
 | 
						|
   //| in the in string.                                                |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,const string replacement,const int count)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, replacement, count, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the recent        |
 | 
						|
   //| "replacement" pattern, starting at the character position        |
 | 
						|
   //| "startat.".                                                      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,const string replacement,const int count,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'replacement' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- A little code to grab a cached parsed replacement object
 | 
						|
      RegexReplacement *repl=m_replref.Get();
 | 
						|
      if(repl==NULL || !(repl.Pattern()==replacement))
 | 
						|
        {
 | 
						|
         repl=RegexParser::ParseReplacement(replacement,m_caps,m_capsize,m_capnames,this.m_roptions);
 | 
						|
         if(CheckPointer(m_replref.Get())==POINTER_DYNAMIC)
 | 
						|
           {
 | 
						|
            delete m_replref.Get();
 | 
						|
           }
 | 
						|
         m_replref.Set(repl);
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return repl.Replace(GetPointer(this), in, count, startat);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the "replacement" |
 | 
						|
   //| pattern ".".                                                     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,MatchEvaluator evaluator)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, pattern, evaluator, None, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern " with the recent       |
 | 
						|
   //| "replacement" pattern, starting at the first character ".".      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,MatchEvaluator evaluator,const RegexOptions options)
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return Replace(in, pattern, evaluator, options, DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern " with the recent       |
 | 
						|
   //| "replacement" pattern, starting at the first character ".".      |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static string Replace(const string in,const string pattern,MatchEvaluator evaluator,const RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex regex(pattern,options,matchTimeout,true);
 | 
						|
      string result=regex.Replace(in,evaluator);
 | 
						|
      //--- return result
 | 
						|
      return (result);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the recent        |
 | 
						|
   //| "replacement" pattern, starting at the first character position  |
 | 
						|
   //| ".".                                                             |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,MatchEvaluator evaluator)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result  
 | 
						|
      return Replace(in, evaluator, -1, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the "pattern" with the recent        |
 | 
						|
   //| "replacement" pattern, starting at the first character position  |
 | 
						|
   //| ".".                                                             |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,MatchEvaluator evaluator,const int count)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result 
 | 
						|
      return Replace(in, evaluator, count, UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Replaces all occurrences of the (previouly defined) "pattern"    |
 | 
						|
   //| with the recent "replacement" pattern, starting at the character |
 | 
						|
   //| position "startat."                                              |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Replace(const string in,MatchEvaluator evaluator,const int count,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      //--- return result 
 | 
						|
      return RegexReplacement::Replace(evaluator, GetPointer(this), in, count, startat);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by "pattern".     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void Split(string &result[],const string in,const string pattern)
 | 
						|
     {
 | 
						|
      Split(result,in,pattern,None,DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by "pattern".     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void Split(string &result[],const string in,const string pattern,RegexOptions options)
 | 
						|
     {
 | 
						|
      Split(result,in,pattern,options,DefaultMatchTimeout);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by "pattern".     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void Split(string &result[],const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | 
						|
     {
 | 
						|
      Regex regex(pattern,options,matchTimeout,true);
 | 
						|
      regex.Split(result,in);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by a previous     |
 | 
						|
   //| "pattern".                                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void Split(string &result[],const string in)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return 
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      Split(result,in,0,UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by a previous     |
 | 
						|
   //| "pattern".                                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void Split(string &result[],const string in,const int count)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return 
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      RegexReplacement::Split(result,GetPointer(this),in,count,UseOptionR() ? StringLen(in) : 0);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Splits the "in" string at the position defined by a previous     |
 | 
						|
   //| "pattern".                                                       |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void Split(string &result[],const string in,const int count,const int startat)
 | 
						|
     {
 | 
						|
      if(in==NULL)
 | 
						|
        {
 | 
						|
         Print("Argument 'in' = NULL.");
 | 
						|
         //--- return 
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      RegexReplacement::Split(result,GetPointer(this),in,count,startat);
 | 
						|
     }
 | 
						|
protected:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| InitializeReferences.                                            |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void InitializeReferences()
 | 
						|
     {
 | 
						|
      if(m_refsInitialized)
 | 
						|
        {
 | 
						|
         Print("Internal error! On file:'"+__FILE__+"'; in function:'"+__FUNCTION__+"'.");
 | 
						|
         //--- return
 | 
						|
         return;
 | 
						|
        }
 | 
						|
      m_refsInitialized=true;
 | 
						|
      m_runnerref  = new RunnerReference();
 | 
						|
      m_replref    = new ReplacementReference();
 | 
						|
     }
 | 
						|
public:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Internal worker called by all the  APIs.                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Match *Run(const bool quick,const int prevlen,const string in,const int beginning,const int length,const int startat)
 | 
						|
     {
 | 
						|
      Match *match;
 | 
						|
      RegexRunner *runner=NULL;
 | 
						|
      if(startat<0 || startat>StringLen(in))
 | 
						|
        {
 | 
						|
         Print("Argument 'start' out of range.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      if(length<0 || length>StringLen(in))
 | 
						|
        {
 | 
						|
         Print("Argument 'length' out of range.");
 | 
						|
         //--- return NULL
 | 
						|
         return (NULL);
 | 
						|
        }
 | 
						|
      bool fromCache=false;
 | 
						|
      //--- There may be a cached runner; grab ownership of it if we can.
 | 
						|
      if(m_runnerref!=NULL)
 | 
						|
        {
 | 
						|
         fromCache=true;
 | 
						|
         runner=m_runnerref.Get();
 | 
						|
        }
 | 
						|
      //--- Create a RegexRunner instance if we need to
 | 
						|
      if(runner==NULL)
 | 
						|
        {
 | 
						|
         fromCache=false;
 | 
						|
         //--- Use the compiled RegexRunner factory if the code was compiled to MSIL
 | 
						|
         runner=new RegexInterpreter(m_code);
 | 
						|
        }
 | 
						|
      //--- Do the scan starting at the requested position            
 | 
						|
      match=runner.Scan(GetPointer(this),in,beginning,beginning+length,startat,prevlen,quick,m_internalMatchTimeout);
 | 
						|
      if(m_runnerref!=NULL && !fromCache)
 | 
						|
        {
 | 
						|
         if(CheckPointer(m_runnerref.Get())==POINTER_DYNAMIC)
 | 
						|
           {
 | 
						|
            delete m_runnerref.Get();
 | 
						|
           }
 | 
						|
         //--- Release or fill the cache slot
 | 
						|
         m_runnerref.Set(runner);
 | 
						|
        }
 | 
						|
      else if(!fromCache)
 | 
						|
        {
 | 
						|
         delete runner;
 | 
						|
        }
 | 
						|
#ifdef _DEBUG
 | 
						|
      if(Debug() && match!=NULL)
 | 
						|
        {
 | 
						|
         match.Dump();
 | 
						|
        }
 | 
						|
#endif
 | 
						|
      //--- return result
 | 
						|
      return (match);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Find code cache based on options+pattern.                        |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static CachedCodeEntry *LookupCachedAndUpdate(const string key)
 | 
						|
     {
 | 
						|
      for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | 
						|
        {
 | 
						|
         if(current.Value().Key()==key)
 | 
						|
           {
 | 
						|
            //--- If we find an entry in the cache, move it to the head at the same time. 
 | 
						|
            m_livecode.Remove(current);
 | 
						|
            m_livecode.AddFirst(current);
 | 
						|
            //--- retrun result
 | 
						|
            return (current.Value());
 | 
						|
           }
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return (NULL);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Add current code to the cache.                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   CachedCodeEntry *CacheCode(const string key)
 | 
						|
     {
 | 
						|
      CachedCodeEntry *newcached=NULL;
 | 
						|
      //--- first look for it in the cache and move it to the head
 | 
						|
      for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | 
						|
        {
 | 
						|
         if(current.Value().Key()==key)
 | 
						|
           {
 | 
						|
            m_livecode.Remove(current);
 | 
						|
            m_livecode.AddFirst(current);
 | 
						|
            //--- return result
 | 
						|
            return (current.Value());
 | 
						|
           }
 | 
						|
        }
 | 
						|
      //--- it wasn't in the cache, so we'll add a new one.  Shortcut out for the case where cacheSize is zero.
 | 
						|
      if(m_cacheSize!=0)
 | 
						|
        {
 | 
						|
         newcached=new CachedCodeEntry(key,m_capnames,m_capslist,m_code,m_caps,m_capsize,m_runnerref,m_replref);
 | 
						|
         m_livecode.AddFirst(newcached);
 | 
						|
         if(m_livecode.Count()>m_cacheSize)
 | 
						|
           {
 | 
						|
            m_livecode.RemoveLast();
 | 
						|
           }
 | 
						|
        }
 | 
						|
      //--- return result
 | 
						|
      return (newcached);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Delete all objects in cache.                                     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   static void ClearCache()
 | 
						|
     {
 | 
						|
      IEnumerator<CachedCodeEntry*>*en=m_livecode.GetEnumerator();
 | 
						|
      while(en.MoveNext())
 | 
						|
        {
 | 
						|
         if(CheckPointer(en.Current())==POINTER_DYNAMIC)
 | 
						|
           {
 | 
						|
            if(CheckPointer(en.Current().RunnerRef().Get().RunRegex())==POINTER_DYNAMIC)
 | 
						|
              {
 | 
						|
               delete en.Current().RunnerRef().Get().RunRegex();
 | 
						|
              }
 | 
						|
            delete en.Current();
 | 
						|
           }
 | 
						|
        }
 | 
						|
      delete en;
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| True if the O option was set.                                    |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool UseOptionC()
 | 
						|
     {
 | 
						|
      return(m_roptions) != 0;
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| True if the L option was set.                                    |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool UseOptionR()
 | 
						|
     {
 | 
						|
      return(m_roptions & RightToLeft) != 0;
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| UseOptionInvariant.                                              |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool UseOptionInvariant()
 | 
						|
     {
 | 
						|
      return(m_roptions) != 0;
 | 
						|
     }
 | 
						|
#ifdef _DEBUG
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| True if the regex has debugging enabled.                         |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   bool Debug()
 | 
						|
     {
 | 
						|
      //--- return result
 | 
						|
      return((m_roptions &Debug) != 0);
 | 
						|
     }
 | 
						|
#endif
 | 
						|
  };
 | 
						|
static const TimeSpan   Regex::MaximumMatchTimeout=TimeSpan::FromMilliseconds(Int32::MaxValue-1);
 | 
						|
static const TimeSpan   Regex::InfiniteMatchTimeout(0,0,0,0,-1);
 | 
						|
static const string Regex::DefaultMatchTimeout_ConfigKeyName="REGEX_DEFAULT_MATCH_TIMEOUT";
 | 
						|
static const TimeSpan   Regex::FallbackDefaultMatchTimeout=Regex::InfiniteMatchTimeout;
 | 
						|
static const TimeSpan   Regex::DefaultMatchTimeout=Regex::InitDefaultMatchTimeout();
 | 
						|
static LinkedList<CachedCodeEntry*>Regex::m_livecode();
 | 
						|
static int Regex::m_cacheSize=15;
 | 
						|
static const int Regex::MaxOptionShift=10;
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Purpose: Used to cache byte codes or compiled factories.         |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class CachedCodeEntry : public IComparable
 | 
						|
  {
 | 
						|
private:
 | 
						|
   string            m_key;
 | 
						|
   RegexCode        *m_code;
 | 
						|
   Dictionary<int,int>*m_caps;
 | 
						|
   Dictionary<string,int>*m_capnames;
 | 
						|
   string            m_capslist[];
 | 
						|
   int               m_capsize;
 | 
						|
   RunnerReference *m_runnerref;
 | 
						|
   ReplacementReference *m_replref;
 | 
						|
public:
 | 
						|
   //--- Constructors:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Constructor with parameters.                                     |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                     CachedCodeEntry(const string key,Dictionary<string,int>*capnames,const string &capslist[],
 | 
						|
                                                       RegexCode *code,Dictionary<int,int>*caps,const int capsize,
 | 
						|
                                                       RunnerReference *runner,ReplacementReference *repl)
 | 
						|
     {
 | 
						|
      m_key=key;
 | 
						|
      m_capnames=capnames;
 | 
						|
      ArrayCopy(m_capslist,capslist);
 | 
						|
      m_code= code;
 | 
						|
      m_caps= caps;
 | 
						|
      m_capsize=capsize;
 | 
						|
      m_runnerref=runner;
 | 
						|
      m_replref=repl;
 | 
						|
     }
 | 
						|
   //--- Destructors:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| destructor without parameters.                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
                    ~CachedCodeEntry()
 | 
						|
     {
 | 
						|
      if(CheckPointer(m_code)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_code;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_caps)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_caps;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_capnames)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_capnames;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_replref)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_replref;
 | 
						|
        }
 | 
						|
      if(CheckPointer(m_runnerref)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_runnerref;
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //--- Methods:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the runnerref.                                              |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RunnerReference *RunnerRef()
 | 
						|
     {
 | 
						|
      //--- reurn runnerref
 | 
						|
      return (m_runnerref);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the replref.                                                |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   ReplacementReference *ReplRef()
 | 
						|
     {
 | 
						|
      //--- return replref
 | 
						|
      return (m_replref);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the key.                                                    |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   string Key()
 | 
						|
     {
 | 
						|
      //--- return key
 | 
						|
      return (m_key);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the caps.                                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Dictionary<int,int>*Caps()
 | 
						|
     {
 | 
						|
      //--- return caps
 | 
						|
      return (m_caps);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the capnames.                                               |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   Dictionary<string,int>*CapNames()
 | 
						|
     {
 | 
						|
      //--- return capnames
 | 
						|
      return (m_capnames);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the capsize.                                                |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   int CapSize()
 | 
						|
     {
 | 
						|
      //--- retrun capsize
 | 
						|
      return (m_capsize);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the code.                                                   |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RegexCode *Code()
 | 
						|
     {
 | 
						|
      //--- return code
 | 
						|
      return (m_code);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Gets the caplist.                                                |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void GetCapList(string &array[])
 | 
						|
     {
 | 
						|
      ArrayCopy(array,m_capslist);
 | 
						|
     }
 | 
						|
  };
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Used to cache a weak reference in a threadsafe way.              |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class ReplacementReference
 | 
						|
  {
 | 
						|
private:
 | 
						|
   RegexReplacement *m_obj;
 | 
						|
public:
 | 
						|
   //--- Destructors:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Destructor without parameters.                                   |
 | 
						|
   //+------------------------------------------------------------------+   
 | 
						|
                    ~ReplacementReference()
 | 
						|
     {
 | 
						|
      if(CheckPointer(m_obj)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_obj;
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //--- Methods:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Get RegexReplacement.                                            |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RegexReplacement *Get()
 | 
						|
     {
 | 
						|
      //--- return pointer
 | 
						|
      return (m_obj);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Set RegexReplacement.                                            |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void      Set(RegexReplacement *obj)
 | 
						|
     {
 | 
						|
      m_obj=obj;
 | 
						|
     }
 | 
						|
  };
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Used to cache one exclusive runner reference.                    |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class RunnerReference
 | 
						|
  {
 | 
						|
private:
 | 
						|
   RegexRunner      *m_obj;
 | 
						|
public:
 | 
						|
   //--- Destructors:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Destructor without parameters.                                   |
 | 
						|
   //+------------------------------------------------------------------+   
 | 
						|
                    ~RunnerReference()
 | 
						|
     {
 | 
						|
      if(CheckPointer(m_obj)==POINTER_DYNAMIC)
 | 
						|
        {
 | 
						|
         delete m_obj;
 | 
						|
        }
 | 
						|
     }
 | 
						|
   //--- Methods:
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Get RegexRunner.                                                 |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   RegexRunner *Get()
 | 
						|
     {
 | 
						|
      //--- return pointer
 | 
						|
      return (m_obj);
 | 
						|
     }
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   //| Set RegexRunner.                                                 |
 | 
						|
   //+------------------------------------------------------------------+
 | 
						|
   void Set(RegexRunner *obj)
 | 
						|
     {
 | 
						|
      m_obj=obj;
 | 
						|
     }
 | 
						|
  };
 | 
						|
//+------------------------------------------------------------------+
 |