| [18] | 1 | Unit TextSearchQuery; | 
|---|
|  | 2 |  | 
|---|
|  | 3 | // NewView - a new OS/2 Help Viewer | 
|---|
|  | 4 | // Copyright 2003 Aaron Lawrence (aaronl at consultant dot com) | 
|---|
|  | 5 | // This software is released under the Gnu Public License - see readme.txt | 
|---|
|  | 6 |  | 
|---|
|  | 7 | Interface | 
|---|
|  | 8 |  | 
|---|
|  | 9 | // Encapsulates a parsed search query. | 
|---|
|  | 10 |  | 
|---|
|  | 11 | uses | 
|---|
| [33] | 12 | Classes, | 
|---|
|  | 13 | SysUtils; | 
|---|
| [18] | 14 |  | 
|---|
|  | 15 | Type | 
|---|
|  | 16 | ESearchSyntaxError = class( Exception ) | 
|---|
|  | 17 | end; | 
|---|
|  | 18 |  | 
|---|
|  | 19 | TSearchTermCombineMethod = | 
|---|
|  | 20 | ( | 
|---|
|  | 21 | cmOptional, | 
|---|
|  | 22 | cmRequired, | 
|---|
|  | 23 | cmExcluded | 
|---|
|  | 24 | ); | 
|---|
|  | 25 |  | 
|---|
|  | 26 | TSearchTerm = class | 
|---|
|  | 27 | Text: string; | 
|---|
|  | 28 | Parts: TStringList; | 
|---|
|  | 29 | CombineMethod: TSearchTermCombineMethod; | 
|---|
|  | 30 |  | 
|---|
|  | 31 | constructor Create( const TheText: string; | 
|---|
|  | 32 | const TheCombineMethod: TSearchTermCombineMethod ); | 
|---|
|  | 33 | destructor Destroy; override; | 
|---|
|  | 34 | end; | 
|---|
|  | 35 |  | 
|---|
|  | 36 | TTextSearchQuery = class | 
|---|
|  | 37 | protected | 
|---|
|  | 38 | Terms: TList; | 
|---|
|  | 39 | function GetTerm( Index: longint ): TSearchTerm; | 
|---|
|  | 40 | function GetTermCount: longint; | 
|---|
|  | 41 | public | 
|---|
|  | 42 | constructor Create( const SearchString: string ); | 
|---|
|  | 43 | destructor Destroy; override; | 
|---|
|  | 44 |  | 
|---|
|  | 45 | property Term[ Index: longint ]: TSearchTerm read GetTerm; | 
|---|
|  | 46 | property TermCount: longint read GetTermCount; | 
|---|
|  | 47 | end; | 
|---|
|  | 48 |  | 
|---|
|  | 49 | Implementation | 
|---|
|  | 50 |  | 
|---|
|  | 51 | uses | 
|---|
| [33] | 52 | ACLUtility, | 
|---|
| [116] | 53 | ACLLanguageUnit, | 
|---|
|  | 54 | CharUtilsUnit, | 
|---|
|  | 55 | StringUtilsUnit, | 
|---|
|  | 56 | DebugUnit; | 
|---|
| [18] | 57 |  | 
|---|
|  | 58 | var | 
|---|
|  | 59 | QueryErrorMissingWord1: string; | 
|---|
|  | 60 | QueryErrorMissingWord2: string; | 
|---|
|  | 61 |  | 
|---|
|  | 62 | Procedure OnLanguageEvent( Language: TLanguageFile; | 
|---|
|  | 63 | const Apply: boolean ); | 
|---|
|  | 64 | begin | 
|---|
|  | 65 |  | 
|---|
|  | 66 | Language.Prefix := 'SearchQuery.'; | 
|---|
|  | 67 | Language.LL( Apply, QueryErrorMissingWord1, 'QueryErrorMissingWord1', 'No search word given after ' ); | 
|---|
|  | 68 | Language.LL( Apply, QueryErrorMissingWord2, 'QueryErrorMissingWord2', ' before ' ); | 
|---|
|  | 69 | end; | 
|---|
|  | 70 |  | 
|---|
|  | 71 | constructor TTextSearchQuery.Create( const SearchString: string ); | 
|---|
|  | 72 | var | 
|---|
|  | 73 | TermText: string; | 
|---|
|  | 74 | CombineMethod: TSearchTermCombineMethod; | 
|---|
|  | 75 | Term: TSearchTerm; | 
|---|
| [116] | 76 | tmpTerms : TStringList; | 
|---|
|  | 77 | i : integer; | 
|---|
| [18] | 78 | begin | 
|---|
|  | 79 | Terms := TList.Create; | 
|---|
|  | 80 | try | 
|---|
| [116] | 81 | tmpTerms := TStringList.Create; | 
|---|
|  | 82 | StrExtractStringsQuoted(tmpTerms, SearchString); | 
|---|
|  | 83 |  | 
|---|
|  | 84 | for i := 0 to tmpTerms.count-1 do | 
|---|
| [18] | 85 | begin | 
|---|
| [116] | 86 | TermText := tmpTerms[i]; | 
|---|
| [18] | 87 |  | 
|---|
|  | 88 | // Check for modifiers: | 
|---|
|  | 89 | //  + word must be matched | 
|---|
|  | 90 | //  - word must not be matched | 
|---|
|  | 91 | case TermText[ 1 ] of | 
|---|
|  | 92 | '+': | 
|---|
|  | 93 | CombineMethod := cmRequired; | 
|---|
|  | 94 | '-': | 
|---|
|  | 95 | CombineMethod := cmExcluded; | 
|---|
|  | 96 | else | 
|---|
|  | 97 | CombineMethod := cmOptional; | 
|---|
|  | 98 | end; | 
|---|
|  | 99 |  | 
|---|
|  | 100 | if CombineMethod <> cmOptional then | 
|---|
|  | 101 | begin | 
|---|
|  | 102 | // delete + or - | 
|---|
|  | 103 | if Length( TermText ) = 1 then | 
|---|
| [116] | 104 | if (i < tmpTerms.count-1) then | 
|---|
|  | 105 | raise ESearchSyntaxError.Create( QueryErrorMissingWord1 | 
|---|
|  | 106 | + StrInDoubleQuotes(TermText) | 
|---|
|  | 107 | + QueryErrorMissingWord2 | 
|---|
|  | 108 | + StrInDoubleQuotes(tmpTerms[i+1]) ) | 
|---|
|  | 109 | else | 
|---|
|  | 110 | raise ESearchSyntaxError.Create( QueryErrorMissingWord1 | 
|---|
|  | 111 | + StrInDoubleQuotes(TermText)); | 
|---|
| [18] | 112 | Delete( TermText, 1, 1 ); | 
|---|
|  | 113 | end; | 
|---|
|  | 114 |  | 
|---|
|  | 115 | Term := TSearchTerm.Create( TermText, | 
|---|
|  | 116 | CombineMethod ); | 
|---|
|  | 117 | Terms.Add( Term ); | 
|---|
|  | 118 | end; | 
|---|
| [116] | 119 | tmpTerms.Destroy; | 
|---|
| [18] | 120 | except | 
|---|
| [116] | 121 | tmpTerms.Destroy; | 
|---|
| [18] | 122 | Destroy; // clean up | 
|---|
|  | 123 | raise; // reraise exception | 
|---|
|  | 124 | end; | 
|---|
|  | 125 | end; | 
|---|
|  | 126 |  | 
|---|
|  | 127 | destructor TTextSearchQuery.Destroy; | 
|---|
|  | 128 | begin | 
|---|
|  | 129 | DestroyListObjects( Terms ); | 
|---|
|  | 130 | Terms.Destroy; | 
|---|
|  | 131 | end; | 
|---|
|  | 132 |  | 
|---|
|  | 133 | function TTextSearchQuery.GetTerm( index: longint ): TSearchTerm; | 
|---|
|  | 134 | begin | 
|---|
|  | 135 | Result := Terms[ Index ]; | 
|---|
|  | 136 | end; | 
|---|
|  | 137 |  | 
|---|
|  | 138 | function TTextSearchQuery.GetTermCount: longint; | 
|---|
|  | 139 | begin | 
|---|
|  | 140 | Result := Terms.Count; | 
|---|
|  | 141 | end; | 
|---|
|  | 142 |  | 
|---|
|  | 143 | constructor TSearchTerm.Create( const TheText: string; | 
|---|
|  | 144 | const TheCombineMethod: TSearchTermCombineMethod ); | 
|---|
|  | 145 | var | 
|---|
|  | 146 | TermParseIndex: longint; | 
|---|
|  | 147 | TermChar: char; | 
|---|
|  | 148 | TermPart: string; | 
|---|
|  | 149 | begin | 
|---|
|  | 150 | Parts := TStringList.Create; | 
|---|
|  | 151 |  | 
|---|
|  | 152 | Text := TheText; | 
|---|
|  | 153 | CombineMethod := TheCombineMethod; | 
|---|
|  | 154 |  | 
|---|
|  | 155 | // Break out each part of the term as IPF does: | 
|---|
|  | 156 | // consecutive alphanumeric chars become a "word" | 
|---|
|  | 157 | // but each symbol is a separate word, and symbols break | 
|---|
|  | 158 | // up alphanumerics into multiple words. e.g. | 
|---|
|  | 159 | // CAKE_SAUSAGE becomes three words in IPF, | 
|---|
|  | 160 | // one each for "CAKE" "_" and "SAUSAGE" | 
|---|
|  | 161 |  | 
|---|
|  | 162 | TermParseIndex := 1; | 
|---|
|  | 163 | while TermParseIndex <= Length( Text ) do | 
|---|
|  | 164 | begin | 
|---|
|  | 165 | // collect alphanumeric chars | 
|---|
|  | 166 | TermPart := ''; | 
|---|
|  | 167 | while TermParseIndex <= Length( Text ) do | 
|---|
|  | 168 | begin | 
|---|
|  | 169 | TermChar := Text[ TermParseIndex ]; | 
|---|
| [116] | 170 | if  (    CharIsAlpha( TermChar ) | 
|---|
|  | 171 | or CharIsDigit( TermChar ) ) then | 
|---|
| [18] | 172 | begin | 
|---|
|  | 173 | // alpha numeric, collect it | 
|---|
|  | 174 | TermPart := TermPart + TermChar; | 
|---|
|  | 175 | inc( TermParseIndex ); | 
|---|
|  | 176 | end | 
|---|
|  | 177 | else | 
|---|
|  | 178 | begin | 
|---|
|  | 179 | // not alpha numeric, so stop | 
|---|
|  | 180 | break; | 
|---|
|  | 181 | end; | 
|---|
|  | 182 | end; | 
|---|
|  | 183 | if Length( TermPart ) > 0 then | 
|---|
|  | 184 | begin | 
|---|
|  | 185 | Parts.Add( TermPart ); // add collected alphanumeric part | 
|---|
|  | 186 | end; | 
|---|
|  | 187 |  | 
|---|
|  | 188 | if TermParseIndex <= Length( Text ) then | 
|---|
|  | 189 | begin | 
|---|
|  | 190 | // must be a symbol, | 
|---|
|  | 191 | // each symbol (excluding space) is an individual item | 
|---|
|  | 192 | if Text[ TermParseIndex ] <> ' ' then | 
|---|
|  | 193 | Parts.Add( Text[ TermParseIndex ] ); | 
|---|
|  | 194 | inc( TermParseIndex ); | 
|---|
|  | 195 | end; | 
|---|
|  | 196 |  | 
|---|
|  | 197 | end; | 
|---|
|  | 198 |  | 
|---|
|  | 199 | end; | 
|---|
|  | 200 |  | 
|---|
|  | 201 | destructor TSearchTerm.Destroy; | 
|---|
|  | 202 | begin | 
|---|
|  | 203 | Parts.Destroy; | 
|---|
|  | 204 | end; | 
|---|
|  | 205 |  | 
|---|
|  | 206 | Initialization | 
|---|
|  | 207 | RegisterProcForLanguages( OnLanguageEvent ); | 
|---|
|  | 208 | End. | 
|---|