3 // namespace: System.Text.RegularExpressions
4 // file: quicksearch.cs
6 // Authors: Dan Lewis (dlewis@gmx.co.uk)
7 // Juraj Skripsky (juraj@hotfeet.ch)
10 // (c) 2007 Juraj Skripsky
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
37 namespace System.Text.RegularExpressions {
38 internal class QuickSearch {
39 // simplified boyer-moore for fast substring matching
40 // (for short strings, we use simple scans)
41 public QuickSearch (string str, bool ignore)
42 : this(str, ignore, false)
46 public QuickSearch (string str, bool ignore, bool reverse) {
48 this.len = str.Length;
50 this.reverse = reverse;
55 // create the shift table only for "long" search strings
60 public string String {
68 public bool IgnoreCase {
69 get { return ignore; }
72 public int Search (string text, int start, int end) {
81 if ( ptr > text.Length)
86 // use simple scan for a single-character search string
91 if(str[0] == GetChar(text[ptr]))
106 while (str[i] == GetChar(text[ptr - len +1 + i]))
109 return ptr - len + 1;
114 ptr -= GetShiftDistance (text[ptr - len ]);
124 // use simple scan for a single-character search string
129 if(str[0] == GetChar(text[ptr]))
137 if (end > text.Length - len)
138 end = text.Length - len;
143 while (str[i] == GetChar(text[ptr + i]))
150 ptr += GetShiftDistance (text[ptr + len]);
162 private void SetupShiftTable () {
163 bool needsExtendedTable = len > (byte.MaxValue - 1);
166 for (int i = 0; i < len; i++) {
168 if (cur <= (char)byte.MaxValue) {
169 if ((byte)cur > maxLowChar)
170 maxLowChar = (byte)cur;
172 needsExtendedTable = true;
175 shift = new byte [maxLowChar + 1];
176 if (needsExtendedTable)
177 shiftExtended = new Hashtable ();
179 for (int i = 0, j = len; i < len; i++, j--) {
180 char c = str [(!reverse ? i : j - 1)];
181 if (c < shift.Length) {
182 if (j < byte.MaxValue) {
186 shift [c] = byte.MaxValue;
189 shiftExtended [c] = j;
193 private int GetShiftDistance (char c) {
198 if (c < shift.Length) {
199 int dist = shift [c];
203 if (dist != byte.MaxValue)
207 if (c < (char)byte.MaxValue)
211 if (shiftExtended == null)
214 object s = shiftExtended [c];
215 return (s != null ? (int)s : len + 1);
218 private char GetChar(char c) {
219 return (!ignore ? c : Char.ToLower(c));
225 private bool reverse;
227 // shift[idx] contains value x means
228 // x == 0 => shift dist. == len + 1
229 // x == byte.Maxvalue => shift dist. >= 255, look it up in shiftExtended
230 // otherwise => shift dist. == x
231 private byte[] shift;
232 private Hashtable shiftExtended;
233 private readonly static int THRESHOLD = 5;