Grammalecte  Hex Artifact Content

Artifact aaa0229431355a564fcd9483abef920c857ab2fa3ad726e980e4e8b47f30d0e9:


0000: 23 20 53 70 65 6c 6c 63 68 65 63 6b 65 72 0a 23  # Spellchecker.#
0010: 20 57 72 61 70 70 65 72 20 66 6f 72 20 74 68 65   Wrapper for the
0020: 20 49 42 44 41 57 47 20 63 6c 61 73 73 2e 0a 23   IBDAWG class..#
0030: 20 55 73 65 66 75 6c 20 74 6f 20 63 68 65 63 6b   Useful to check
0040: 20 73 65 76 65 72 61 6c 20 64 69 63 74 69 6f 6e   several diction
0050: 61 72 69 65 73 20 61 74 20 6f 6e 63 65 2e 0a 0a  aries at once...
0060: 23 20 54 6f 20 61 76 6f 69 64 20 69 74 65 72 61  # To avoid itera
0070: 74 69 6e 67 20 6f 76 65 72 20 61 20 70 69 6c 65  ting over a pile
0080: 20 6f 66 20 64 69 63 74 69 6f 6e 61 72 69 65 73   of dictionaries
0090: 2c 20 69 74 20 69 73 20 61 73 73 75 6d 65 64 20  , it is assumed 
00a0: 74 68 61 74 20 33 20 61 72 65 20 65 6e 6f 75 67  that 3 are enoug
00b0: 68 3a 0a 23 20 2d 20 74 68 65 20 6d 61 69 6e 20  h:.# - the main 
00c0: 64 69 63 74 69 6f 6e 61 72 79 2c 20 62 75 6e 64  dictionary, bund
00d0: 6c 65 64 20 77 69 74 68 20 74 68 65 20 70 61 63  led with the pac
00e0: 6b 61 67 65 0a 23 20 2d 20 74 68 65 20 65 78 74  kage.# - the ext
00f0: 65 6e 64 65 64 20 64 69 63 74 69 6f 6e 61 72 79  ended dictionary
0100: 2c 20 61 64 64 65 64 20 62 79 20 61 6e 20 6f 72  , added by an or
0110: 67 61 6e 69 7a 61 74 69 6f 6e 0a 23 20 2d 20 74  ganization.# - t
0120: 68 65 20 70 65 72 73 6f 6e 61 6c 20 64 69 63 74  he personal dict
0130: 69 6f 6e 61 72 79 2c 20 63 72 65 61 74 65 64 20  ionary, created 
0140: 62 79 20 74 68 65 20 75 73 65 72 20 66 6f 72 20  by the user for 
0150: 69 74 73 20 6f 77 6e 20 63 6f 6e 76 65 6e 69 65  its own convenie
0160: 6e 63 65 0a 0a 0a 69 6d 70 6f 72 74 20 74 72 61  nce...import tra
0170: 63 65 62 61 63 6b 0a 0a 66 72 6f 6d 20 2e 20 69  ceback..from . i
0180: 6d 70 6f 72 74 20 69 62 64 61 77 67 0a 66 72 6f  mport ibdawg.fro
0190: 6d 20 2e 20 69 6d 70 6f 72 74 20 74 6f 6b 65 6e  m . import token
01a0: 69 7a 65 72 0a 0a 0a 64 44 65 66 61 75 6c 74 44  izer...dDefaultD
01b0: 69 63 74 69 6f 6e 61 72 69 65 73 20 3d 20 7b 0a  ictionaries = {.
01c0: 20 20 20 20 22 66 72 22 3a 20 22 66 72 2e 62 64      "fr": "fr.bd
01d0: 69 63 22 2c 0a 20 20 20 20 22 65 6e 22 3a 20 22  ic",.    "en": "
01e0: 65 6e 2e 62 64 69 63 22 0a 7d 0a 0a 0a 63 6c 61  en.bdic".}...cla
01f0: 73 73 20 53 70 65 6c 6c 43 68 65 63 6b 65 72 20  ss SpellChecker 
0200: 28 29 3a 0a 0a 20 20 20 20 64 65 66 20 5f 5f 69  ():..    def __i
0210: 6e 69 74 5f 5f 20 28 73 65 6c 66 2c 20 73 4c 61  nit__ (self, sLa
0220: 6e 67 43 6f 64 65 2c 20 73 66 4d 61 69 6e 44 69  ngCode, sfMainDi
0230: 63 3d 22 22 2c 20 73 66 45 78 74 65 6e 64 65 64  c="", sfExtended
0240: 44 69 63 3d 22 22 2c 20 73 66 50 65 72 73 6f 6e  Dic="", sfPerson
0250: 61 6c 44 69 63 3d 22 22 29 3a 0a 20 20 20 20 20  alDic=""):.     
0260: 20 20 20 22 72 65 74 75 72 6e 73 20 54 72 75 65     "returns True
0270: 20 69 66 20 74 68 65 20 6d 61 69 6e 20 64 69 63   if the main dic
0280: 74 69 6f 6e 61 72 79 20 69 73 20 6c 6f 61 64 65  tionary is loade
0290: 64 22 0a 20 20 20 20 20 20 20 20 73 65 6c 66 2e  d".        self.
02a0: 73 4c 61 6e 67 43 6f 64 65 20 3d 20 73 4c 61 6e  sLangCode = sLan
02b0: 67 43 6f 64 65 0a 20 20 20 20 20 20 20 20 69 66  gCode.        if
02c0: 20 6e 6f 74 20 73 66 4d 61 69 6e 44 69 63 3a 0a   not sfMainDic:.
02d0: 20 20 20 20 20 20 20 20 20 20 20 20 73 66 4d 61              sfMa
02e0: 69 6e 44 69 63 20 3d 20 64 44 65 66 61 75 6c 74  inDic = dDefault
02f0: 44 69 63 74 69 6f 6e 61 72 69 65 73 2e 67 65 74  Dictionaries.get
0300: 28 73 4c 61 6e 67 43 6f 64 65 2c 20 22 22 29 0a  (sLangCode, "").
0310: 20 20 20 20 20 20 20 20 73 65 6c 66 2e 6f 4d 61          self.oMa
0320: 69 6e 44 69 63 20 3d 20 73 65 6c 66 2e 5f 6c 6f  inDic = self._lo
0330: 61 64 44 69 63 74 69 6f 6e 61 72 79 28 73 66 4d  adDictionary(sfM
0340: 61 69 6e 44 69 63 2c 20 54 72 75 65 29 0a 20 20  ainDic, True).  
0350: 20 20 20 20 20 20 73 65 6c 66 2e 6f 45 78 74 65        self.oExte
0360: 6e 64 65 64 44 69 63 20 3d 20 73 65 6c 66 2e 5f  ndedDic = self._
0370: 6c 6f 61 64 44 69 63 74 69 6f 6e 61 72 79 28 73  loadDictionary(s
0380: 66 45 78 74 65 6e 64 65 64 44 69 63 29 0a 20 20  fExtendedDic).  
0390: 20 20 20 20 20 20 73 65 6c 66 2e 6f 50 65 72 73        self.oPers
03a0: 6f 6e 61 6c 44 69 63 20 3d 20 73 65 6c 66 2e 5f  onalDic = self._
03b0: 6c 6f 61 64 44 69 63 74 69 6f 6e 61 72 79 28 73  loadDictionary(s
03c0: 66 50 65 72 73 6f 6e 61 6c 44 69 63 29 0a 20 20  fPersonalDic).  
03d0: 20 20 20 20 20 20 73 65 6c 66 2e 6f 54 6f 6b 65        self.oToke
03e0: 6e 69 7a 65 72 20 3d 20 4e 6f 6e 65 0a 0a 20 20  nizer = None..  
03f0: 20 20 64 65 66 20 5f 6c 6f 61 64 44 69 63 74 69    def _loadDicti
0400: 6f 6e 61 72 79 20 28 73 65 6c 66 2c 20 73 6f 75  onary (self, sou
0410: 72 63 65 2c 20 62 4e 65 63 65 73 73 61 72 79 3d  rce, bNecessary=
0420: 46 61 6c 73 65 29 3a 0a 20 20 20 20 20 20 20 20  False):.        
0430: 22 72 65 74 75 72 6e 73 20 61 6e 20 49 42 44 41  "returns an IBDA
0440: 57 47 20 6f 62 6a 65 63 74 22 0a 20 20 20 20 20  WG object".     
0450: 20 20 20 69 66 20 6e 6f 74 20 73 6f 75 72 63 65     if not source
0460: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  :.            re
0470: 74 75 72 6e 20 4e 6f 6e 65 0a 20 20 20 20 20 20  turn None.      
0480: 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20    try:.         
0490: 20 20 20 72 65 74 75 72 6e 20 69 62 64 61 77 67     return ibdawg
04a0: 2e 49 42 44 41 57 47 28 73 6f 75 72 63 65 29 0a  .IBDAWG(source).
04b0: 20 20 20 20 20 20 20 20 65 78 63 65 70 74 20 45          except E
04c0: 78 63 65 70 74 69 6f 6e 20 61 73 20 65 3a 0a 20  xception as e:. 
04d0: 20 20 20 20 20 20 20 20 20 20 20 69 66 20 62 4e             if bN
04e0: 65 63 65 73 73 61 72 79 3a 0a 20 20 20 20 20 20  ecessary:.      
04f0: 20 20 20 20 20 20 20 20 20 20 72 61 69 73 65 20            raise 
0500: 45 78 63 65 70 74 69 6f 6e 28 73 74 72 28 65 29  Exception(str(e)
0510: 2c 20 22 45 72 72 6f 72 3a 20 3c 22 20 2b 20 73  , "Error: <" + s
0520: 74 72 28 73 6f 75 72 63 65 29 20 2b 20 22 3e 20  tr(source) + "> 
0530: 6e 6f 74 20 6c 6f 61 64 65 64 2e 22 29 0a 20 20  not loaded.").  
0540: 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28            print(
0550: 22 45 72 72 6f 72 3a 20 3c 22 20 2b 20 73 74 72  "Error: <" + str
0560: 28 73 6f 75 72 63 65 29 20 2b 20 22 3e 20 6e 6f  (source) + "> no
0570: 74 20 6c 6f 61 64 65 64 2e 22 29 0a 20 20 20 20  t loaded.").    
0580: 20 20 20 20 20 20 20 20 74 72 61 63 65 62 61 63          tracebac
0590: 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29 0a 20 20  k.print_exc().  
05a0: 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e            return
05b0: 20 4e 6f 6e 65 0a 0a 20 20 20 20 64 65 66 20 6c   None..    def l
05c0: 6f 61 64 54 6f 6b 65 6e 69 7a 65 72 20 28 73 65  oadTokenizer (se
05d0: 6c 66 29 3a 0a 20 20 20 20 20 20 20 20 73 65 6c  lf):.        sel
05e0: 66 2e 6f 54 6f 6b 65 6e 69 7a 65 72 20 3d 20 74  f.oTokenizer = t
05f0: 6f 6b 65 6e 69 7a 65 72 2e 54 6f 6b 65 6e 69 7a  okenizer.Tokeniz
0600: 65 72 28 73 65 6c 66 2e 73 4c 61 6e 67 43 6f 64  er(self.sLangCod
0610: 65 29 0a 0a 20 20 20 20 64 65 66 20 67 65 74 54  e)..    def getT
0620: 6f 6b 65 6e 69 7a 65 72 20 28 73 65 6c 66 29 3a  okenizer (self):
0630: 0a 20 20 20 20 20 20 20 20 69 66 20 6e 6f 74 20  .        if not 
0640: 73 65 6c 66 2e 6f 54 6f 6b 65 6e 69 7a 65 72 3a  self.oTokenizer:
0650: 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 65 6c  .            sel
0660: 66 2e 6c 6f 61 64 54 6f 6b 65 6e 69 7a 65 72 28  f.loadTokenizer(
0670: 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  ).        return
0680: 20 73 65 6c 66 2e 6f 54 6f 6b 65 6e 69 7a 65 72   self.oTokenizer
0690: 0a 0a 20 20 20 20 64 65 66 20 73 65 74 4d 61 69  ..    def setMai
06a0: 6e 44 69 63 74 69 6f 6e 61 72 79 20 28 73 65 6c  nDictionary (sel
06b0: 66 2c 20 73 6f 75 72 63 65 29 3a 0a 20 20 20 20  f, source):.    
06c0: 20 20 20 20 22 72 65 74 75 72 6e 73 20 54 72 75      "returns Tru
06d0: 65 20 69 66 20 74 68 65 20 64 69 63 74 69 6f 6e  e if the diction
06e0: 61 72 79 20 69 73 20 6c 6f 61 64 65 64 22 0a 20  ary is loaded". 
06f0: 20 20 20 20 20 20 20 73 65 6c 66 2e 6f 4d 61 69         self.oMai
0700: 6e 44 69 63 20 3d 20 73 65 6c 66 2e 5f 6c 6f 61  nDic = self._loa
0710: 64 44 69 63 74 69 6f 6e 61 72 79 28 73 6f 75 72  dDictionary(sour
0720: 63 65 29 0a 20 20 20 20 20 20 20 20 72 65 74 75  ce).        retu
0730: 72 6e 20 62 6f 6f 6c 28 73 65 6c 66 2e 6f 4d 61  rn bool(self.oMa
0740: 69 6e 44 69 63 29 0a 20 20 20 20 20 20 20 20 20  inDic).         
0750: 20 20 20 0a 20 20 20 20 64 65 66 20 73 65 74 45     .    def setE
0760: 78 74 65 6e 64 65 64 44 69 63 74 69 6f 6e 61 72  xtendedDictionar
0770: 79 20 28 73 65 6c 66 2c 20 73 6f 75 72 63 65 29  y (self, source)
0780: 3a 0a 20 20 20 20 20 20 20 20 22 72 65 74 75 72  :.        "retur
0790: 6e 73 20 54 72 75 65 20 69 66 20 74 68 65 20 64  ns True if the d
07a0: 69 63 74 69 6f 6e 61 72 79 20 69 73 20 6c 6f 61  ictionary is loa
07b0: 64 65 64 22 0a 20 20 20 20 20 20 20 20 73 65 6c  ded".        sel
07c0: 66 2e 6f 45 78 74 65 6e 64 65 64 44 69 63 20 3d  f.oExtendedDic =
07d0: 20 73 65 6c 66 2e 5f 6c 6f 61 64 44 69 63 74 69   self._loadDicti
07e0: 6f 6e 61 72 79 28 73 6f 75 72 63 65 29 0a 20 20  onary(source).  
07f0: 20 20 20 20 20 20 72 65 74 75 72 6e 20 62 6f 6f        return boo
0800: 6c 28 73 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64  l(self.oExtended
0810: 44 69 63 29 0a 0a 20 20 20 20 64 65 66 20 73 65  Dic)..    def se
0820: 74 50 65 72 73 6f 6e 61 6c 44 69 63 74 69 6f 6e  tPersonalDiction
0830: 61 72 79 20 28 73 65 6c 66 2c 20 73 6f 75 72 63  ary (self, sourc
0840: 65 29 3a 0a 20 20 20 20 20 20 20 20 22 72 65 74  e):.        "ret
0850: 75 72 6e 73 20 54 72 75 65 20 69 66 20 74 68 65  urns True if the
0860: 20 64 69 63 74 69 6f 6e 61 72 79 20 69 73 20 6c   dictionary is l
0870: 6f 61 64 65 64 22 0a 20 20 20 20 20 20 20 20 73  oaded".        s
0880: 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44 69 63  elf.oPersonalDic
0890: 20 3d 20 73 65 6c 66 2e 5f 6c 6f 61 64 44 69 63   = self._loadDic
08a0: 74 69 6f 6e 61 72 79 28 73 6f 75 72 63 65 29 0a  tionary(source).
08b0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 62          return b
08c0: 6f 6f 6c 28 73 65 6c 66 2e 6f 50 65 72 73 6f 6e  ool(self.oPerson
08d0: 61 6c 44 69 63 29 0a 0a 20 20 20 20 23 20 70 61  alDic)..    # pa
08e0: 72 73 65 20 74 65 78 74 20 66 75 6e 63 74 69 6f  rse text functio
08f0: 6e 73 0a 0a 20 20 20 20 64 65 66 20 70 61 72 73  ns..    def pars
0900: 65 50 61 72 61 67 72 61 70 68 20 28 73 65 6c 66  eParagraph (self
0910: 2c 20 73 54 65 78 74 2c 20 62 53 70 65 6c 6c 53  , sText, bSpellS
0920: 75 67 67 3d 46 61 6c 73 65 29 3a 0a 20 20 20 20  ugg=False):.    
0930: 20 20 20 20 69 66 20 6e 6f 74 20 73 65 6c 66 2e      if not self.
0940: 6f 54 6f 6b 65 6e 69 7a 65 72 3a 0a 20 20 20 20  oTokenizer:.    
0950: 20 20 20 20 20 20 20 20 73 65 6c 66 2e 6c 6f 61          self.loa
0960: 64 54 6f 6b 65 6e 69 7a 65 72 28 29 0a 20 20 20  dTokenizer().   
0970: 20 20 20 20 20 61 53 70 65 6c 6c 45 72 72 73 20       aSpellErrs 
0980: 3d 20 5b 5d 0a 20 20 20 20 20 20 20 20 66 6f 72  = [].        for
0990: 20 64 54 6f 6b 65 6e 20 69 6e 20 73 65 6c 66 2e   dToken in self.
09a0: 6f 54 6f 6b 65 6e 69 7a 65 72 2e 67 65 6e 54 6f  oTokenizer.genTo
09b0: 6b 65 6e 73 28 73 54 65 78 74 29 3a 0a 20 20 20  kens(sText):.   
09c0: 20 20 20 20 20 20 20 20 20 69 66 20 64 54 6f 6b           if dTok
09d0: 65 6e 5b 27 73 54 79 70 65 27 5d 20 3d 3d 20 22  en['sType'] == "
09e0: 57 4f 52 44 22 20 61 6e 64 20 6e 6f 74 20 73 65  WORD" and not se
09f0: 6c 66 2e 69 73 56 61 6c 69 64 54 6f 6b 65 6e 28  lf.isValidToken(
0a00: 64 54 6f 6b 65 6e 5b 27 73 56 61 6c 75 65 27 5d  dToken['sValue']
0a10: 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ):.             
0a20: 20 20 20 69 66 20 62 53 70 65 6c 6c 53 75 67 67     if bSpellSugg
0a30: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
0a40: 20 20 20 20 20 20 64 54 6f 6b 65 6e 5b 27 61 53        dToken['aS
0a50: 75 67 67 65 73 74 69 6f 6e 73 27 5d 20 3d 20 5b  uggestions'] = [
0a60: 5d 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ].              
0a70: 20 20 20 20 20 20 66 6f 72 20 6c 53 75 67 67 20        for lSugg 
0a80: 69 6e 20 73 65 6c 66 2e 73 75 67 67 65 73 74 28  in self.suggest(
0a90: 64 54 6f 6b 65 6e 5b 27 73 56 61 6c 75 65 27 5d  dToken['sValue']
0aa0: 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ):.             
0ab0: 20 20 20 20 20 20 20 20 20 20 20 64 54 6f 6b 65             dToke
0ac0: 6e 5b 27 61 53 75 67 67 65 73 74 69 6f 6e 73 27  n['aSuggestions'
0ad0: 5d 2e 65 78 74 65 6e 64 28 6c 53 75 67 67 29 0a  ].extend(lSugg).
0ae0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0af0: 61 53 70 65 6c 6c 45 72 72 73 2e 61 70 70 65 6e  aSpellErrs.appen
0b00: 64 28 64 54 6f 6b 65 6e 29 0a 20 20 20 20 20 20  d(dToken).      
0b10: 20 20 72 65 74 75 72 6e 20 61 53 70 65 6c 6c 45    return aSpellE
0b20: 72 72 73 0a 0a 20 20 20 20 64 65 66 20 63 6f 75  rrs..    def cou
0b30: 6e 74 57 6f 72 64 73 4f 63 63 75 72 72 65 6e 63  ntWordsOccurrenc
0b40: 65 73 20 28 73 65 6c 66 2c 20 73 54 65 78 74 2c  es (self, sText,
0b50: 20 62 42 79 4c 65 6d 6d 61 3d 46 61 6c 73 65 2c   bByLemma=False,
0b60: 20 62 4f 6e 6c 79 55 6e 6b 6e 6f 77 6e 57 6f 72   bOnlyUnknownWor
0b70: 64 73 3d 46 61 6c 73 65 2c 20 64 57 6f 72 64 3d  ds=False, dWord=
0b80: 7b 7d 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20  {}):.        if 
0b90: 6e 6f 74 20 73 65 6c 66 2e 6f 54 6f 6b 65 6e 69  not self.oTokeni
0ba0: 7a 65 72 3a 0a 20 20 20 20 20 20 20 20 20 20 20  zer:.           
0bb0: 20 73 65 6c 66 2e 6c 6f 61 64 54 6f 6b 65 6e 69   self.loadTokeni
0bc0: 7a 65 72 28 29 0a 20 20 20 20 20 20 20 20 66 6f  zer().        fo
0bd0: 72 20 64 54 6f 6b 65 6e 20 69 6e 20 73 65 6c 66  r dToken in self
0be0: 2e 6f 54 6f 6b 65 6e 69 7a 65 72 2e 67 65 6e 54  .oTokenizer.genT
0bf0: 6f 6b 65 6e 73 28 73 54 65 78 74 29 3a 0a 20 20  okens(sText):.  
0c00: 20 20 20 20 20 20 20 20 20 20 69 66 20 64 54 6f            if dTo
0c10: 6b 65 6e 5b 27 73 54 79 70 65 27 5d 20 3d 3d 20  ken['sType'] == 
0c20: 22 57 4f 52 44 22 3a 0a 20 20 20 20 20 20 20 20  "WORD":.        
0c30: 20 20 20 20 20 20 20 20 69 66 20 62 4f 6e 6c 79          if bOnly
0c40: 55 6e 6b 6e 6f 77 6e 57 6f 72 64 73 3a 0a 20 20  UnknownWords:.  
0c50: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c60: 20 20 69 66 20 6e 6f 74 20 73 65 6c 66 2e 69 73    if not self.is
0c70: 56 61 6c 69 64 54 6f 6b 65 6e 28 64 54 6f 6b 65  ValidToken(dToke
0c80: 6e 5b 27 73 56 61 6c 75 65 27 5d 29 3a 0a 20 20  n['sValue']):.  
0c90: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ca0: 20 20 20 20 20 20 64 57 6f 72 64 5b 64 54 6f 6b        dWord[dTok
0cb0: 65 6e 5b 27 73 56 61 6c 75 65 27 5d 5d 20 3d 20  en['sValue']] = 
0cc0: 64 57 6f 72 64 2e 67 65 74 28 64 54 6f 6b 65 6e  dWord.get(dToken
0cd0: 5b 27 73 56 61 6c 75 65 27 5d 2c 20 30 29 20 2b  ['sValue'], 0) +
0ce0: 20 31 0a 20 20 20 20 20 20 20 20 20 20 20 20 20   1.             
0cf0: 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20     else:.       
0d00: 20 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20               if 
0d10: 6e 6f 74 20 62 42 79 4c 65 6d 6d 61 3a 0a 20 20  not bByLemma:.  
0d20: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d30: 20 20 20 20 20 20 64 57 6f 72 64 5b 64 54 6f 6b        dWord[dTok
0d40: 65 6e 5b 27 73 56 61 6c 75 65 27 5d 5d 20 3d 20  en['sValue']] = 
0d50: 64 57 6f 72 64 2e 67 65 74 28 64 54 6f 6b 65 6e  dWord.get(dToken
0d60: 5b 27 73 56 61 6c 75 65 27 5d 2c 20 30 29 20 2b  ['sValue'], 0) +
0d70: 20 31 0a 20 20 20 20 20 20 20 20 20 20 20 20 20   1.             
0d80: 20 20 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20         else:.   
0d90: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0da0: 20 20 20 20 20 66 6f 72 20 73 4c 65 6d 6d 61 20       for sLemma 
0db0: 69 6e 20 73 65 6c 66 2e 67 65 74 4c 65 6d 6d 61  in self.getLemma
0dc0: 28 64 54 6f 6b 65 6e 5b 27 73 56 61 6c 75 65 27  (dToken['sValue'
0dd0: 5d 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ]):.            
0de0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0df0: 64 57 6f 72 64 5b 73 4c 65 6d 6d 61 5d 20 3d 20  dWord[sLemma] = 
0e00: 64 57 6f 72 64 2e 67 65 74 28 73 4c 65 6d 6d 61  dWord.get(sLemma
0e10: 2c 20 30 29 20 2b 20 31 0a 20 20 20 20 20 20 20  , 0) + 1.       
0e20: 20 72 65 74 75 72 6e 20 64 57 6f 72 64 0a 0a 20   return dWord.. 
0e30: 20 20 20 23 20 49 42 44 41 57 47 20 66 75 6e 63     # IBDAWG func
0e40: 74 69 6f 6e 73 0a 0a 20 20 20 20 64 65 66 20 69  tions..    def i
0e50: 73 56 61 6c 69 64 54 6f 6b 65 6e 20 28 73 65 6c  sValidToken (sel
0e60: 66 2c 20 73 54 6f 6b 65 6e 29 3a 0a 20 20 20 20  f, sToken):.    
0e70: 20 20 20 20 22 63 68 65 63 6b 73 20 69 66 20 73      "checks if s
0e80: 54 6f 6b 65 6e 20 69 73 20 76 61 6c 69 64 20 28  Token is valid (
0e90: 69 66 20 74 68 65 72 65 20 69 73 20 68 79 70 68  if there is hyph
0ea0: 65 6e 73 20 69 6e 20 73 54 6f 6b 65 6e 2c 20 73  ens in sToken, s
0eb0: 54 6f 6b 65 6e 20 69 73 20 73 70 6c 69 74 2c 20  Token is split, 
0ec0: 65 61 63 68 20 70 61 72 74 20 69 73 20 63 68 65  each part is che
0ed0: 63 6b 65 64 29 22 0a 20 20 20 20 20 20 20 20 69  cked)".        i
0ee0: 66 20 73 65 6c 66 2e 6f 4d 61 69 6e 44 69 63 2e  f self.oMainDic.
0ef0: 69 73 56 61 6c 69 64 54 6f 6b 65 6e 28 73 54 6f  isValidToken(sTo
0f00: 6b 65 6e 29 3a 0a 20 20 20 20 20 20 20 20 20 20  ken):.          
0f10: 20 20 72 65 74 75 72 6e 20 54 72 75 65 0a 20 20    return True.  
0f20: 20 20 20 20 20 20 69 66 20 73 65 6c 66 2e 6f 45        if self.oE
0f30: 78 74 65 6e 64 65 64 44 69 63 20 61 6e 64 20 73  xtendedDic and s
0f40: 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64 44 69 63  elf.oExtendedDic
0f50: 2e 69 73 56 61 6c 69 64 54 6f 6b 65 6e 28 73 54  .isValidToken(sT
0f60: 6f 6b 65 6e 29 3a 0a 20 20 20 20 20 20 20 20 20  oken):.         
0f70: 20 20 20 72 65 74 75 72 6e 20 54 72 75 65 0a 20     return True. 
0f80: 20 20 20 20 20 20 20 69 66 20 73 65 6c 66 2e 6f         if self.o
0f90: 50 65 72 73 6f 6e 61 6c 44 69 63 20 61 6e 64 20  PersonalDic and 
0fa0: 73 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44 69  self.oPersonalDi
0fb0: 63 2e 69 73 56 61 6c 69 64 54 6f 6b 65 6e 28 73  c.isValidToken(s
0fc0: 54 6f 6b 65 6e 29 3a 0a 20 20 20 20 20 20 20 20  Token):.        
0fd0: 20 20 20 20 72 65 74 75 72 6e 20 54 72 75 65 0a      return True.
0fe0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 46          return F
0ff0: 61 6c 73 65 0a 0a 20 20 20 20 64 65 66 20 69 73  alse..    def is
1000: 56 61 6c 69 64 20 28 73 65 6c 66 2c 20 73 57 6f  Valid (self, sWo
1010: 72 64 29 3a 0a 20 20 20 20 20 20 20 20 22 63 68  rd):.        "ch
1020: 65 63 6b 73 20 69 66 20 73 57 6f 72 64 20 69 73  ecks if sWord is
1030: 20 76 61 6c 69 64 20 28 64 69 66 66 65 72 65 6e   valid (differen
1040: 74 20 63 61 73 69 6e 67 20 74 65 73 74 65 64 20  t casing tested 
1050: 69 66 20 74 68 65 20 66 69 72 73 74 20 6c 65 74  if the first let
1060: 74 65 72 20 69 73 20 61 20 63 61 70 69 74 61 6c  ter is a capital
1070: 29 22 0a 20 20 20 20 20 20 20 20 69 66 20 73 65  )".        if se
1080: 6c 66 2e 6f 4d 61 69 6e 44 69 63 2e 69 73 56 61  lf.oMainDic.isVa
1090: 6c 69 64 28 73 57 6f 72 64 29 3a 0a 20 20 20 20  lid(sWord):.    
10a0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 54          return T
10b0: 72 75 65 0a 20 20 20 20 20 20 20 20 69 66 20 73  rue.        if s
10c0: 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64 44 69 63  elf.oExtendedDic
10d0: 20 61 6e 64 20 73 65 6c 66 2e 6f 45 78 74 65 6e   and self.oExten
10e0: 64 65 64 44 69 63 2e 69 73 56 61 6c 69 64 28 73  dedDic.isValid(s
10f0: 57 6f 72 64 29 3a 0a 20 20 20 20 20 20 20 20 20  Word):.         
1100: 20 20 20 72 65 74 75 72 6e 20 54 72 75 65 0a 20     return True. 
1110: 20 20 20 20 20 20 20 69 66 20 73 65 6c 66 2e 6f         if self.o
1120: 50 65 72 73 6f 6e 61 6c 44 69 63 20 61 6e 64 20  PersonalDic and 
1130: 73 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44 69  self.oPersonalDi
1140: 63 2e 69 73 56 61 6c 69 64 28 73 57 6f 72 64 29  c.isValid(sWord)
1150: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  :.            re
1160: 74 75 72 6e 20 54 72 75 65 0a 20 20 20 20 20 20  turn True.      
1170: 20 20 72 65 74 75 72 6e 20 46 61 6c 73 65 0a 0a    return False..
1180: 20 20 20 20 64 65 66 20 6c 6f 6f 6b 75 70 20 28      def lookup (
1190: 73 65 6c 66 2c 20 73 57 6f 72 64 29 3a 0a 20 20  self, sWord):.  
11a0: 20 20 20 20 20 20 22 63 68 65 63 6b 73 20 69 66        "checks if
11b0: 20 73 57 6f 72 64 20 69 73 20 69 6e 20 64 69 63   sWord is in dic
11c0: 74 69 6f 6e 61 72 79 20 61 73 20 69 73 20 28 73  tionary as is (s
11d0: 74 72 69 63 74 20 76 65 72 69 66 69 63 61 74 69  trict verificati
11e0: 6f 6e 29 22 0a 20 20 20 20 20 20 20 20 69 66 20  on)".        if 
11f0: 73 65 6c 66 2e 6f 4d 61 69 6e 44 69 63 2e 6c 6f  self.oMainDic.lo
1200: 6f 6b 75 70 28 73 57 6f 72 64 29 3a 0a 20 20 20  okup(sWord):.   
1210: 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20           return 
1220: 54 72 75 65 0a 20 20 20 20 20 20 20 20 69 66 20  True.        if 
1230: 73 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64 44 69  self.oExtendedDi
1240: 63 20 61 6e 64 20 73 65 6c 66 2e 6f 45 78 74 65  c and self.oExte
1250: 6e 64 65 64 44 69 63 2e 6c 6f 6f 6b 75 70 28 73  ndedDic.lookup(s
1260: 57 6f 72 64 29 3a 0a 20 20 20 20 20 20 20 20 20  Word):.         
1270: 20 20 20 72 65 74 75 72 6e 20 54 72 75 65 0a 20     return True. 
1280: 20 20 20 20 20 20 20 69 66 20 73 65 6c 66 2e 6f         if self.o
1290: 50 65 72 73 6f 6e 61 6c 44 69 63 20 61 6e 64 20  PersonalDic and 
12a0: 73 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44 69  self.oPersonalDi
12b0: 63 2e 6c 6f 6f 6b 75 70 28 73 57 6f 72 64 29 3a  c.lookup(sWord):
12c0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74  .            ret
12d0: 75 72 6e 20 54 72 75 65 0a 20 20 20 20 20 20 20  urn True.       
12e0: 20 72 65 74 75 72 6e 20 46 61 6c 73 65 0a 0a 20   return False.. 
12f0: 20 20 20 64 65 66 20 67 65 74 4d 6f 72 70 68 20     def getMorph 
1300: 28 73 65 6c 66 2c 20 73 57 6f 72 64 29 3a 0a 20  (self, sWord):. 
1310: 20 20 20 20 20 20 20 22 72 65 74 72 69 65 76 65         "retrieve
1320: 73 20 6d 6f 72 70 68 6f 6c 6f 67 69 65 73 20 6c  s morphologies l
1330: 69 73 74 2c 20 64 69 66 66 65 72 65 6e 74 20 63  ist, different c
1340: 61 73 69 6e 67 20 61 6c 6c 6f 77 65 64 22 0a 20  asing allowed". 
1350: 20 20 20 20 20 20 20 6c 52 65 73 75 6c 74 20 3d         lResult =
1360: 20 73 65 6c 66 2e 6f 4d 61 69 6e 44 69 63 2e 67   self.oMainDic.g
1370: 65 74 4d 6f 72 70 68 28 73 57 6f 72 64 29 0a 20  etMorph(sWord). 
1380: 20 20 20 20 20 20 20 69 66 20 73 65 6c 66 2e 6f         if self.o
1390: 45 78 74 65 6e 64 65 64 44 69 63 3a 0a 20 20 20  ExtendedDic:.   
13a0: 20 20 20 20 20 20 20 20 20 6c 52 65 73 75 6c 74           lResult
13b0: 2e 65 78 74 65 6e 64 28 73 65 6c 66 2e 6f 45 78  .extend(self.oEx
13c0: 74 65 6e 64 65 64 44 69 63 2e 67 65 74 4d 6f 72  tendedDic.getMor
13d0: 70 68 28 73 57 6f 72 64 29 29 0a 20 20 20 20 20  ph(sWord)).     
13e0: 20 20 20 69 66 20 73 65 6c 66 2e 6f 50 65 72 73     if self.oPers
13f0: 6f 6e 61 6c 44 69 63 3a 0a 20 20 20 20 20 20 20  onalDic:.       
1400: 20 20 20 20 20 6c 52 65 73 75 6c 74 2e 65 78 74       lResult.ext
1410: 65 6e 64 28 73 65 6c 66 2e 6f 50 65 72 73 6f 6e  end(self.oPerson
1420: 61 6c 44 69 63 2e 67 65 74 4d 6f 72 70 68 28 73  alDic.getMorph(s
1430: 57 6f 72 64 29 29 0a 20 20 20 20 20 20 20 20 72  Word)).        r
1440: 65 74 75 72 6e 20 6c 52 65 73 75 6c 74 0a 0a 20  eturn lResult.. 
1450: 20 20 20 64 65 66 20 67 65 74 4c 65 6d 6d 61 20     def getLemma 
1460: 28 73 65 6c 66 2c 20 73 57 6f 72 64 29 3a 0a 20  (self, sWord):. 
1470: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 73 65         return se
1480: 74 28 5b 20 73 5b 31 3a 73 2e 66 69 6e 64 28 22  t([ s[1:s.find("
1490: 20 22 29 5d 20 20 66 6f 72 20 73 20 69 6e 20 73   ")]  for s in s
14a0: 65 6c 66 2e 67 65 74 4d 6f 72 70 68 28 73 57 6f  elf.getMorph(sWo
14b0: 72 64 29 20 5d 29 0a 0a 20 20 20 20 64 65 66 20  rd) ])..    def 
14c0: 73 75 67 67 65 73 74 20 28 73 65 6c 66 2c 20 73  suggest (self, s
14d0: 57 6f 72 64 2c 20 6e 53 75 67 67 4c 69 6d 69 74  Word, nSuggLimit
14e0: 3d 31 30 29 3a 0a 20 20 20 20 20 20 20 20 22 67  =10):.        "g
14f0: 65 6e 65 72 61 74 6f 72 3a 20 72 65 74 75 72 6e  enerator: return
1500: 73 20 31 2c 20 32 20 6f 72 20 33 20 6c 69 73 74  s 1, 2 or 3 list
1510: 73 20 6f 66 20 73 75 67 67 65 73 74 69 6f 6e 73  s of suggestions
1520: 22 0a 20 20 20 20 20 20 20 20 79 69 65 6c 64 20  ".        yield 
1530: 73 65 6c 66 2e 6f 4d 61 69 6e 44 69 63 2e 73 75  self.oMainDic.su
1540: 67 67 65 73 74 28 73 57 6f 72 64 2c 20 6e 53 75  ggest(sWord, nSu
1550: 67 67 4c 69 6d 69 74 29 0a 20 20 20 20 20 20 20  ggLimit).       
1560: 20 69 66 20 73 65 6c 66 2e 6f 45 78 74 65 6e 64   if self.oExtend
1570: 65 64 44 69 63 3a 0a 20 20 20 20 20 20 20 20 20  edDic:.         
1580: 20 20 20 79 69 65 6c 64 20 73 65 6c 66 2e 6f 45     yield self.oE
1590: 78 74 65 6e 64 65 64 44 69 63 2e 73 75 67 67 65  xtendedDic.sugge
15a0: 73 74 28 73 57 6f 72 64 2c 20 6e 53 75 67 67 4c  st(sWord, nSuggL
15b0: 69 6d 69 74 29 0a 20 20 20 20 20 20 20 20 69 66  imit).        if
15c0: 20 73 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44   self.oPersonalD
15d0: 69 63 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ic:.            
15e0: 79 69 65 6c 64 20 73 65 6c 66 2e 6f 50 65 72 73  yield self.oPers
15f0: 6f 6e 61 6c 44 69 63 2e 73 75 67 67 65 73 74 28  onalDic.suggest(
1600: 73 57 6f 72 64 2c 20 6e 53 75 67 67 4c 69 6d 69  sWord, nSuggLimi
1610: 74 29 0a 0a 20 20 20 20 64 65 66 20 73 65 6c 65  t)..    def sele
1620: 63 74 20 28 73 65 6c 66 2c 20 73 50 61 74 74 65  ct (self, sPatte
1630: 72 6e 3d 22 22 29 3a 0a 20 20 20 20 20 20 20 20  rn=""):.        
1640: 22 67 65 6e 65 72 61 74 6f 72 3a 20 72 65 74 75  "generator: retu
1650: 72 6e 73 20 61 6c 6c 20 65 6e 74 72 69 65 73 20  rns all entries 
1660: 77 68 69 63 68 20 6d 6f 72 70 68 6f 6c 6f 67 79  which morphology
1670: 20 66 69 74 73 20 3c 73 50 61 74 74 65 72 6e 3e   fits <sPattern>
1680: 22 0a 20 20 20 20 20 20 20 20 79 69 65 6c 64 20  ".        yield 
1690: 66 72 6f 6d 20 73 65 6c 66 2e 6f 4d 61 69 6e 44  from self.oMainD
16a0: 69 63 2e 73 65 6c 65 63 74 28 73 50 61 74 74 65  ic.select(sPatte
16b0: 72 6e 29 0a 20 20 20 20 20 20 20 20 69 66 20 73  rn).        if s
16c0: 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64 44 69 63  elf.oExtendedDic
16d0: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 79 69  :.            yi
16e0: 65 6c 64 20 66 72 6f 6d 20 73 65 6c 66 2e 6f 45  eld from self.oE
16f0: 78 74 65 6e 64 65 64 44 69 63 2e 73 65 6c 65 63  xtendedDic.selec
1700: 74 28 73 50 61 74 74 65 72 6e 29 0a 20 20 20 20  t(sPattern).    
1710: 20 20 20 20 69 66 20 73 65 6c 66 2e 6f 50 65 72      if self.oPer
1720: 73 6f 6e 61 6c 44 69 63 3a 0a 20 20 20 20 20 20  sonalDic:.      
1730: 20 20 20 20 20 20 79 69 65 6c 64 20 66 72 6f 6d        yield from
1740: 20 73 65 6c 66 2e 6f 50 65 72 73 6f 6e 61 6c 44   self.oPersonalD
1750: 69 63 2e 73 65 6c 65 63 74 28 73 50 61 74 74 65  ic.select(sPatte
1760: 72 6e 29 0a 0a 20 20 20 20 64 65 66 20 64 72 61  rn)..    def dra
1770: 77 50 61 74 68 20 28 73 65 6c 66 2c 20 73 57 6f  wPath (self, sWo
1780: 72 64 29 3a 0a 20 20 20 20 20 20 20 20 73 65 6c  rd):.        sel
1790: 66 2e 6f 4d 61 69 6e 44 69 63 2e 64 72 61 77 50  f.oMainDic.drawP
17a0: 61 74 68 28 73 57 6f 72 64 29 0a 20 20 20 20 20  ath(sWord).     
17b0: 20 20 20 69 66 20 73 65 6c 66 2e 6f 45 78 74 65     if self.oExte
17c0: 6e 64 65 64 44 69 63 3a 0a 20 20 20 20 20 20 20  ndedDic:.       
17d0: 20 20 20 20 20 70 72 69 6e 74 28 22 2d 2d 2d 2d       print("----
17e0: 2d 22 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  -").            
17f0: 73 65 6c 66 2e 6f 45 78 74 65 6e 64 65 64 44 69  self.oExtendedDi
1800: 63 2e 64 72 61 77 50 61 74 68 28 73 57 6f 72 64  c.drawPath(sWord
1810: 29 0a 20 20 20 20 20 20 20 20 69 66 20 73 65 6c  ).        if sel
1820: 66 2e 6f 50 65 72 73 6f 6e 61 6c 44 69 63 3a 0a  f.oPersonalDic:.
1830: 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e              prin
1840: 74 28 22 2d 2d 2d 2d 2d 22 29 0a 20 20 20 20 20  t("-----").     
1850: 20 20 20 20 20 20 20 73 65 6c 66 2e 6f 50 65 72         self.oPer
1860: 73 6f 6e 61 6c 44 69 63 2e 64 72 61 77 50 61 74  sonalDic.drawPat
1870: 68 28 73 57 6f 72 64 29 0a                       h(sWord).