~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/extensions/spellcheck/myspell/src/myspSuggestmgr.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is Mozilla Spellchecker Component.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * David Einstein.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2001
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s): David Einstein <Deinst@world.std.com>
 
23
 *                 Kevin Hendricks <kevin.hendricks@sympatico.ca>
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the MPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the MPL, the GPL or the LGPL.
 
36
 *
 
37
 *  This spellchecker is based on the MySpell spellchecker made for Open Office
 
38
 *  by Kevin Hendricks.  Although the algorithms and code, have changed 
 
39
 *  slightly, the architecture is still the same. The Mozilla implementation
 
40
 *  is designed to be compatible with the Open Office dictionaries.
 
41
 *  Please do not make changes to the affix or dictionary file formats 
 
42
 *  without attempting to coordinate with Kevin.  For more information 
 
43
 *  on the original MySpell see 
 
44
 *  http://whiteboard.openoffice.org/source/browse/whiteboard/lingucomponent/source/spellcheck/myspell/
 
45
 *
 
46
 *  A special thanks and credit goes to Geoff Kuenning
 
47
 * the creator of ispell.  MySpell's affix algorithms were
 
48
 * based on those of ispell which should be noted is
 
49
 * copyright Geoff Kuenning et.al. and now available
 
50
 * under a BSD style license. For more information on ispell
 
51
 * and affix compression in general, please see:
 
52
 * http://www.cs.ucla.edu/ficus-members/geoff/ispell.html
 
53
 * (the home page for ispell)
 
54
 *
 
55
 * ***** END LICENSE BLOCK ***** */
 
56
#include "myspSuggestmgr.h"
 
57
#include "plstr.h"
 
58
#include "nsReadableUtils.h"
 
59
#include "nsMemory.h"
 
60
#include "nsUnicharUtils.h"
 
61
 
 
62
myspSuggestMgr::myspSuggestMgr()
 
63
{
 
64
}
 
65
 
 
66
 
 
67
myspSuggestMgr::~myspSuggestMgr()
 
68
{
 
69
  pAMgr = nsnull;
 
70
  maxSug = 0;
 
71
}
 
72
 
 
73
void 
 
74
myspSuggestMgr::setup(const nsAFlatString &tryme, int maxn, myspAffixMgr *aptr)
 
75
{
 
76
  // register affix manager and check in string of chars to 
 
77
  // try when building candidate suggestions
 
78
  pAMgr = aptr;
 
79
  ctry = tryme;
 
80
  maxSug = maxn;
 
81
}
 
82
 
 
83
 
 
84
// generate suggestions for a mispelled word
 
85
//    pass in address of array of char * pointers
 
86
 
 
87
nsresult myspSuggestMgr::suggest(PRUnichar ***slst,const nsAFlatString &word, PRUint32 *num)
 
88
{
 
89
  NS_ENSURE_ARG_POINTER(num);
 
90
  NS_ENSURE_ARG_POINTER(slst);
 
91
 
 
92
  nsresult res;
 
93
  PRUint32 nsug;
 
94
  PRUint32 i;
 
95
  PRUnichar **wlst;
 
96
  if(!(*slst)){
 
97
    nsug=0;
 
98
    wlst=(PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * maxSug);
 
99
    if(!wlst)
 
100
      return NS_ERROR_OUT_OF_MEMORY;
 
101
    memset(wlst, nsnull, sizeof(PRUnichar*) * maxSug); 
 
102
  }
 
103
  else{
 
104
    wlst=*slst;
 
105
    nsug=*num;
 
106
  }
 
107
 
 
108
  // perhaps we made a typical fault of spelling
 
109
  res = replchars(wlst, word, &nsug);
 
110
 
 
111
  // did we forget to add a char
 
112
  if ((nsug < maxSug) && NS_SUCCEEDED(res)){
 
113
    res = forgotchar(wlst, word, &nsug);
 
114
  }
 
115
 
 
116
  // did we swap the order of chars by mistake
 
117
  if ((nsug < maxSug) && NS_SUCCEEDED(res)){
 
118
    res = swapchar(wlst, word, &nsug);
 
119
  }
 
120
 
 
121
  // did we add a char that should not be there
 
122
  if ((nsug < maxSug) && NS_SUCCEEDED(res)){
 
123
    res = extrachar(wlst, word, &nsug);
 
124
  }
 
125
 
 
126
    // did we just hit the wrong key in place of a good char
 
127
  if ((nsug < maxSug) && NS_SUCCEEDED(res)){
 
128
    res = badchar(wlst, word, &nsug);
 
129
  }
 
130
 
 
131
    // perhaps we forgot to hit space and two words ran together
 
132
  if ((nsug < maxSug) && NS_SUCCEEDED(res)){
 
133
    res = twowords(wlst, word, &nsug);
 
134
  }
 
135
  if(NS_FAILED(res)){
 
136
    for (i=0;i<maxSug; i++)
 
137
      if (wlst[i] != NULL) nsMemory::Free(wlst[i]);
 
138
    nsMemory::Free(wlst);
 
139
    *slst = 0;
 
140
    *num=0;
 
141
  }
 
142
  else{
 
143
    *slst=wlst;
 
144
    *num=nsug;
 
145
  }
 
146
  return res;
 
147
}
 
148
 
 
149
 
 
150
// suggestions for a typical fault of spelling, that
 
151
// differs with more, than 1 letter from the right form.
 
152
nsresult myspSuggestMgr::replchars(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
 
153
{
 
154
  nsString candidate;
 
155
  PRBool cwrd;
 
156
  PRUint32 i,k;
 
157
  PRUint32 startOffset, findOffset;
 
158
 
 
159
  if (word.Length() < 2 || ! pAMgr) return NS_OK;
 
160
 
 
161
  PRUint32 replaceTableLength = pAMgr->getReplaceTableLength();
 
162
  struct mozReplaceTable *replaceTable = pAMgr->getReplaceTable();
 
163
 
 
164
  if (replaceTable == nsnull) return NS_OK;
 
165
 
 
166
  for (i=0; i < replaceTableLength; i++ ) {
 
167
    startOffset = 0;
 
168
 
 
169
    candidate.Assign(word);
 
170
    ToLowerCase(candidate);
 
171
 
 
172
    while ((findOffset = candidate.Find(replaceTable[i].pattern, startOffset)) != -1) {
 
173
      candidate.Assign(word);
 
174
      ToLowerCase(candidate);
 
175
      candidate.Replace(findOffset, replaceTable[i].pattern.Length(), replaceTable[i].replacement);
 
176
 
 
177
      cwrd = PR_TRUE;
 
178
      for(k=0;k < *ns;k++){
 
179
        if (candidate.Equals(wlst[k]) ){ 
 
180
          cwrd = PR_FALSE;
 
181
          break;
 
182
        }
 
183
      }
 
184
 
 
185
      if (cwrd && pAMgr->check(candidate)) {
 
186
        if (*ns < maxSug) {
 
187
          wlst[*ns] = ToNewUnicode(candidate);
 
188
          if(!wlst[*ns])
 
189
            return NS_ERROR_OUT_OF_MEMORY;
 
190
          (*ns)++;
 
191
        } else return NS_OK;
 
192
      }
 
193
 
 
194
      startOffset = findOffset + replaceTable[i].pattern.Length();
 
195
    }
 
196
  }
 
197
 
 
198
  return NS_OK;
 
199
}
 
200
 
 
201
// error is wrong char in place of correct one
 
202
nsresult myspSuggestMgr::badchar(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
 
203
{
 
204
  PRUnichar tmpc;
 
205
  nsAutoString candidate;
 
206
  PRBool cwrd;
 
207
  PRUint32 i,j,k;
 
208
  PRUint32 wl = word.Length();
 
209
  candidate.Assign(word);
 
210
  nsASingleFragmentString::char_iterator candIt;
 
211
  for (i=0,candidate.BeginWriting(candIt); i < wl; i++,candIt++) {
 
212
    tmpc = *candIt;
 
213
    for (j=0; j < ctry.Length(); j++) {
 
214
      if (ctry[j] == tmpc) continue;
 
215
      *candIt = ctry[j];
 
216
      cwrd = PR_TRUE;
 
217
      for(k=0;k < *ns;k++){
 
218
        if (candidate.Equals(wlst[k]) ){ 
 
219
          cwrd = PR_FALSE;
 
220
          break;
 
221
        }
 
222
      }
 
223
      if (cwrd && pAMgr->check(candidate)) {
 
224
        if (*ns < maxSug) {
 
225
          wlst[*ns] = ToNewUnicode(candidate);
 
226
          if(!wlst[*ns])
 
227
            return NS_ERROR_OUT_OF_MEMORY;
 
228
          (*ns)++;
 
229
        } else return NS_OK;
 
230
      }
 
231
      *candIt = tmpc;
 
232
    }
 
233
  }
 
234
  return NS_OK;
 
235
}
 
236
 
 
237
 
 
238
// error is word has an extra letter it does not need 
 
239
nsresult myspSuggestMgr::extrachar(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
 
240
{
 
241
  PRBool cwrd;
 
242
  nsString stCand;
 
243
  nsAutoString candidate;
 
244
  PRUint32 k;
 
245
  PRUint32 wl = word.Length();
 
246
  if (wl < 2) return 0;
 
247
  
 
248
  // try omitting one char of word at a time
 
249
  candidate.Assign(Substring(word,1,wl-1));
 
250
  nsASingleFragmentString::char_iterator r;
 
251
  nsASingleFragmentString::const_char_iterator p,end;
 
252
  word.EndReading(end);
 
253
  
 
254
  for (word.BeginReading(p),candidate.BeginWriting(r);  p != end;  ) {
 
255
    cwrd = PR_TRUE;
 
256
    for(k=0;k < *ns;k++){
 
257
      if (candidate.Equals(wlst[k])){ 
 
258
        cwrd = PR_FALSE;
 
259
        break;
 
260
      }
 
261
    }
 
262
    if (cwrd && pAMgr->check(candidate)) {
 
263
      if (*ns < maxSug) {
 
264
        wlst[*ns] = ToNewUnicode(candidate);
 
265
        if(!wlst[*ns])
 
266
          return NS_ERROR_OUT_OF_MEMORY;
 
267
        (*ns)++;
 
268
      } else return NS_OK;
 
269
    }
 
270
    *r++ = *p++;
 
271
  }
 
272
  return NS_OK;
 
273
}
 
274
 
 
275
 
 
276
// error is mising a letter it needs
 
277
nsresult myspSuggestMgr::forgotchar(PRUnichar **wlst,const nsAFlatString &word, PRUint32 *ns)
 
278
{
 
279
  PRBool cwrd;
 
280
  nsString stCand;
 
281
  nsAutoString candidate;
 
282
  PRUint32 i,k;
 
283
  candidate = NS_LITERAL_STRING(" ") + word;
 
284
  nsASingleFragmentString::char_iterator q;
 
285
  nsASingleFragmentString::const_char_iterator p,end;
 
286
  word.EndReading(end);
 
287
 
 
288
  // try inserting a tryme character before every letter
 
289
  for (word.BeginReading(p), candidate.BeginWriting(q);  p != end;  )  {
 
290
    for ( i = 0;  i < ctry.Length();  i++) {
 
291
      *q = ctry[i];
 
292
      cwrd = PR_TRUE;
 
293
      for(k=0;k < *ns;k++){
 
294
        if (candidate.Equals(wlst[k]) ){ 
 
295
          cwrd = PR_FALSE;
 
296
          break;
 
297
        }
 
298
      }
 
299
      if (cwrd && pAMgr->check(candidate)) {
 
300
        if (*ns < maxSug) {
 
301
          wlst[*ns] = ToNewUnicode(candidate);
 
302
          if(!wlst[*ns])
 
303
            return NS_ERROR_OUT_OF_MEMORY;
 
304
          (*ns)++;
 
305
        } else return NS_OK;
 
306
      }
 
307
    }
 
308
    *q++ = *p++;
 
309
  }
 
310
   
 
311
  // now try adding one to end */
 
312
  for ( i = 0;  i < ctry.Length();  i++) {
 
313
    *q = ctry[i];
 
314
    cwrd = PR_TRUE;
 
315
    for(k=0;k < *ns;k++){
 
316
      if (candidate.Equals(wlst[k])){ 
 
317
        cwrd = PR_FALSE;
 
318
        break;
 
319
      }
 
320
    }
 
321
    if (cwrd && pAMgr->check(candidate)) {
 
322
      if (*ns < maxSug) {
 
323
        wlst[*ns] = ToNewUnicode(candidate);
 
324
        if(!wlst[*ns])
 
325
          return NS_ERROR_OUT_OF_MEMORY;
 
326
        (*ns)++;
 
327
      } else return NS_OK;
 
328
    }
 
329
  }
 
330
  return NS_OK;
 
331
}
 
332
 
 
333
 
 
334
/* error is should have been two words */
 
335
nsresult myspSuggestMgr::twowords(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
 
336
{
 
337
  nsAutoString candidate;
 
338
  PRUint32 pos;
 
339
  PRUint32 wl=word.Length();
 
340
  if (wl < 3) return NS_OK;
 
341
  candidate.Assign(word);
 
342
  nsAutoString temp;
 
343
 
 
344
  // split the string into two pieces after every char
 
345
  // if both pieces are good words make them a suggestion
 
346
  for (pos =  1;  pos < wl;  pos++) {
 
347
    temp.Assign(Substring(candidate,0,pos));
 
348
    if (pAMgr->check(temp)) {
 
349
      temp.Assign(Substring(candidate,pos,wl-pos));
 
350
      if (pAMgr->check(temp)) {
 
351
        if (*ns < maxSug) {
 
352
          candidate.Insert(PRUnichar(' '),pos);
 
353
          wlst[*ns] = ToNewUnicode(candidate);
 
354
          if(!wlst[*ns])
 
355
            return NS_ERROR_OUT_OF_MEMORY;
 
356
          (*ns)++;
 
357
        } else return NS_OK;
 
358
      }
 
359
    }
 
360
  }
 
361
  return NS_OK;
 
362
}
 
363
 
 
364
 
 
365
// error is adjacent letter were swapped
 
366
nsresult myspSuggestMgr::swapchar(PRUnichar **wlst,const nsAFlatString &word, PRUint32 *ns)
 
367
{
 
368
  nsAutoString candidate;
 
369
  PRUnichar     tmpc;
 
370
  PRBool cwrd;
 
371
  PRUint32 k;
 
372
  candidate.Assign(word);
 
373
  nsASingleFragmentString::char_iterator p,q,end;
 
374
  candidate.EndWriting(end);
 
375
 
 
376
  for (candidate.BeginWriting(p),q=p, q++;  q != end;  p++,q++) {
 
377
    tmpc = *p;
 
378
    *p = *q;
 
379
    *q = tmpc;
 
380
    cwrd = PR_TRUE;
 
381
    for(k=0;k < *ns;k++){
 
382
      if (candidate.Equals(wlst[k])){ 
 
383
        cwrd = PR_FALSE;
 
384
        break;
 
385
      }
 
386
    }
 
387
    if (cwrd && pAMgr->check(candidate)) {
 
388
      if (*ns < maxSug) {
 
389
        wlst[*ns] = ToNewUnicode(candidate);
 
390
        if(!wlst[*ns])
 
391
          return NS_ERROR_OUT_OF_MEMORY;
 
392
        (*ns)++;
 
393
      } else return NS_OK;
 
394
    }
 
395
    tmpc = *p;
 
396
    *p = *q;
 
397
    *q = tmpc;
 
398
  }
 
399
  return NS_OK;
 
400
}
 
401