├── README.md ├── .gitattributes ├── LICENSE ├── .gitignore ├── data_maker.py ├── d.py └── dictionary.py /README.md: -------------------------------------------------------------------------------- 1 | # Dictionary 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tushar Jain 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # IPython 77 | profile_default/ 78 | ipython_config.py 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | .dmypy.json 111 | dmypy.json 112 | 113 | # Pyre type checker 114 | .pyre/ 115 | -------------------------------------------------------------------------------- /data_maker.py: -------------------------------------------------------------------------------- 1 | from nltk.corpus import wordnet as wn 2 | import nltk, json 3 | 4 | #from nltk.corpus import words 5 | #not using words.words() because its bullshit 6 | 7 | ''' 8 | TYPES={ 9 | 'CC':'Conjunction', 'CD':'Cardinal Digit', 'DT': 'Determiner', 'EX': 'Existential', 'FW': 'Foreign Word', 10 | 'IN' :'Preposition', 'JJ' :'Adjective', 'JJR': 'Bigger Adjective', 'JJS': 'Superlative Adjective', 11 | 'LS' :'List Marker', 'MD' :'Modal', 'NN' :'Singular Noun', 'NNS': 'Plural Noun', 'NNP': 'Singular Proper Noun', 12 | 'NNPS': 'Plural Proper Noun', 'PDT' :'Pre-determiner', 'POS' :'Possesive', 'PRP' :'Personal Pronoun', 13 | 'PRP$': 'Posessive Pronoun', 'RB' :'Adverb', 'RBR': 'Bigger Adverb', 'RBS': 'Superlative Adjective', 14 | 'RP': 'Particle', 'TO': 'N/A', 'UH': 'Interjection', 'VB': 'Verb', 'VBD': 'Verb, Past Tense', 15 | 'VBG': 'Verb, Present','VBN': 'Verb, Past Participle', 'VBP': 'Verb, Singular Present', 16 | 'VBZ': 'Verb, 3rd Person Singular Present', 'WDT': 'WH-determiner', 'WP': 'WH-pronoun', 'WP$': 'Possessive WH-pronoun', 17 | 'WRB': 'WH-abverb' 18 | } 19 | ''' 20 | 21 | 22 | L=[] 23 | f=open('words.txt') 24 | data=f.read() 25 | f.close() 26 | L=data.split('\n') 27 | 28 | 29 | D={} 30 | 31 | empty_words=[] 32 | 33 | 34 | for word in L: 35 | word=word.upper() 36 | D_word={} # {WORD:{'MEANINGS':{...}, 'ANTONYMS':[...], 'SYNONYMS:[...]'}} 37 | 38 | #help(S[0]) 39 | #1/0 40 | 41 | ALL_TYPES={'n':'Noun', 'v':'Verb', 'a':'Adjective','s':'Adjective', 'r':'Adverb'} 42 | 43 | 44 | 45 | MEANINGS={} # 'MEANINGS':{SENSE_NUM_1:[TYPE_1, MEANING, CONTEXT, EXAMPLE], SENSE_NUM_2:[TYPE_2, MEANING, CONTEXT, EXAMPLE]}' 46 | SYNONYMS = set() 47 | ANTONYMS = set() 48 | sense=[] 49 | S=wn.synsets(word) 50 | 51 | 52 | def get_context(syn): 53 | HYPERNYMS=syn.hypernyms() 54 | result=[] 55 | for i in HYPERNYMS: 56 | temp=i.lemma_names() 57 | temp=[' '.join(i.capitalize().split('_')) for i in temp] 58 | result+=temp 59 | 60 | return result 61 | 62 | 63 | for syn in S: 64 | 65 | for l in syn.lemmas(): 66 | temp=' '.join(l.name().capitalize().split('_')) 67 | SYNONYMS.add(temp) 68 | if l.antonyms(): 69 | ANTONYMS.add(l.antonyms()[0].name()) 70 | 71 | syn_name=syn.name().split('.')[0].upper() 72 | if syn_name!=word:continue 73 | 74 | sense_num=int(syn.name().split('.')[-1]) 75 | if sense_num in sense: 76 | continue 77 | 78 | t=ALL_TYPES[syn.pos()] # type 79 | m=syn.definition() # meaning 80 | c=get_context(syn) # context 81 | e=syn.examples() # examples 82 | 83 | temp={sense_num:[t, m, c, e]} 84 | MEANINGS.update(temp) 85 | 86 | try:SYNONYMS.remove(word) 87 | except:pass 88 | try:ANTONYMS.remove(word) 89 | except:pass 90 | SYNONYMS, ANTONYMS=list(SYNONYMS)[:5], list(ANTONYMS)[:5] 91 | if MEANINGS!={} or SYNONYMS!=[]: 92 | D_word={word:{'MEANINGS':MEANINGS,'ANTONYMS':ANTONYMS, 'SYNONYMS':SYNONYMS}} 93 | D.update(D_word) 94 | else: 95 | empty_words+=[word] 96 | 97 | 98 | L=[chr(ord('A')+i) for i in range(26)] 99 | 100 | L=L 101 | for i in L: 102 | D2={} 103 | print(i) 104 | for word in D: 105 | if word[0].upper()==i: 106 | D2.update({word: D[word]}) 107 | 108 | f=open(f'data\\D{i}.json','w') 109 | data=json.dumps(D2) 110 | f.write(data) 111 | f.close() 112 | 113 | f=open('data\\empty_words.txt','w') 114 | f.write('\n'.join(empty_words)) 115 | f.close() -------------------------------------------------------------------------------- /d.py: -------------------------------------------------------------------------------- 1 | import sys, dictionary,os 2 | 3 | dir_name=os.path.dirname(sys.argv[0]) 4 | paths=os.environ['PATH'] 5 | 6 | if dir_name not in paths: 7 | os.environ['PATH']+=os.pathsep+dir_name 8 | 9 | 10 | logo=''' * WELCOME TO * 11 | 12 | -------------------------------+ 13 | ____ _ __ _ | 14 | / __ \(_)____/ /_(_)___ ___| ____ ________ __ 15 | / / / / / ___/ __/ / __ \/ __ \/ __ `/ ___/ / / / 16 | / /_/ / / /__/ /_/ / /_/ / / / / /_/ / / / /_/ / 17 | /_____/_/\___/\__/_/\____/_/ /_/\____/_/ \____/ 18 | | /____/ 19 | | 20 | -------------------------------+ 21 | - TJ Productions 2019''' 22 | 23 | 24 | main_menu=rf''' 25 | 26 | {logo} 27 | 28 | 29 | MAIN MENU- 30 | 31 | 1) Search a word 32 | 2) Add a new word in Database 33 | 3) Read the docs 34 | 4) Quit 35 | 36 | 37 | ''' 38 | 39 | __doc__=r''' 40 | 41 | * D I C T I O N A R Y * 42 | 43 | A command-line program that lets you search meanings of words 44 | in a jiffy, just from your command-line, and that too offline. 45 | 46 | -> DICTIONARY is probably the most advanced command-line english. 47 | 48 | DICTINARY uses an a custom-made database, derived from NLTK library 49 | in Python. In short, the DICTIONARY database is reliable and full of 50 | information. 51 | 52 | You type the word and dictionary will provide you all the information 53 | that it has, regarding that word! 54 | 55 | The usage of this program is also very easy. 56 | 57 | You can use the program in 2 ways. First is to directly open the program 58 | and run it. Second is a faster way, to do your tasks without even having 59 | to open the program. 60 | 61 | First way- 62 | Just run the program and follow on-screen instructions. 63 | 64 | Second way- 65 | Use command-line arguments. Its is the faster way for doing things. 66 | 67 | How to use this method- 68 | a. Make sure this program is in your environment variables 69 | (although the program takes care of this, but still, if you 70 | are unale to operate this program from command-line, you know 71 | what to do) 72 | b. Use this program using arguments such as -S, -A, -H, -D 73 | 74 | c. -S is used for searching a word in dictionary. To use it, 75 | just write 'd -s' and the program will show you the 76 | information regarding that word. Also, even if you don't provide this 77 | -S, argument, still the program will function in the same way as -S 78 | is the default argument. 79 | 80 | d. -A to add a new word. 'd -A' and this command will let you add a 81 | new word in your dictionary. 82 | 83 | e. -D/ -H for help. If you need help regarding how to use this program, 84 | you can use the 'd -D' or 'd -H' command. 85 | 86 | ''' 87 | 88 | def main(): 89 | msg='Enter your choice from 1-4: ' 90 | while True: 91 | os.system('cls') 92 | 93 | print(main_menu) 94 | 95 | choice = input(msg) 96 | if choice =='1': 97 | print('\n\n ** STARTING SEARCH **') 98 | word=input('\nEnter a word: ') 99 | dictionary.search_word(word) 100 | input('Enter to continue...') 101 | 102 | if choice =='2': 103 | print('\n\n ** ADDING NEW WORD **') 104 | dictionary.add_new_word() 105 | input('Enter to continue...') 106 | 107 | if choice == '3': 108 | print('\n\n ** GETTING THE DOCS READY **') 109 | print(__doc__) 110 | input('Enter to continue...') 111 | 112 | if choice =='4': 113 | print('\n\n ** GOODBYE **') 114 | break 115 | 116 | if choice not in ['1', '2','3','4','5']: 117 | msg='Enter only numbers from 1 to 4: ' 118 | else: 119 | msg='Enter your choice: ' 120 | 121 | 122 | 123 | 124 | ALL_ARGS=['--ADD', '-A', '--SEARCH', '-S','-D','--DOC', '-H','--HELP'] 125 | args=sys.argv[1:] 126 | args=[i.upper() for i in args] 127 | 128 | if args==[]: 129 | arg='MAIN' 130 | 131 | elif args[-1] in ALL_ARGS: 132 | arg=args[-1] 133 | else: 134 | arg='-S' 135 | 136 | 137 | 138 | 139 | if arg in ['--ADD','-A']: 140 | dictionary.add_new_word() 141 | 142 | 143 | elif arg=='MAIN': 144 | main() 145 | sys.exit() 146 | 147 | elif arg in ['-D','--DOC','-H','--HELP']: 148 | os.system('cls') 149 | print(__doc__) 150 | 151 | elif arg in ['-S','--SEARCH'] : 152 | try:word=''.join(args.remove(arg)) 153 | except:word=''.join(args) 154 | dictionary.search_word(word) -------------------------------------------------------------------------------- /dictionary.py: -------------------------------------------------------------------------------- 1 | import json, time 2 | import os 3 | from difflib import SequenceMatcher as SM 4 | import tj,sys 5 | from pyunpack import Archive 6 | # import downloader 7 | import urllib.request 8 | 9 | FILE='D.json' 10 | 11 | 12 | cwd=os.path.dirname(__file__) 13 | if cwd!="":os.chdir(cwd) 14 | 15 | D={} 16 | D_List=[] 17 | 18 | 19 | 20 | def setter(): 21 | dir_name=os.path.dirname(sys.argv[0]) 22 | link=r'https://www.dropbox.com/s/qjdgnf6npiqymgs/data.7z?dl=1' 23 | data_file=os.path.join(dir_name, 'data.7z') 24 | print("Data file is: ",data_file) 25 | 26 | # d=downloader.Download(link, data_file) 27 | 28 | try: 29 | print('Trying to recover the data from data.7z file') 30 | Archive(data_file).extractall(dir_name) 31 | print('Data retrival successful, program will now function normally...') 32 | except: 33 | print('Data retrival failed as data.7z was not found...') 34 | print('Trying to download data.7z from internet') 35 | try: 36 | # d.download() 37 | urllib.request.urlretrieve(link, data_file) 38 | Archive(data_file).extractall(dir_name) 39 | except: 40 | print('Could not download the database due to connection issue...') 41 | print('Restart the program, with a proper internet connection...') 42 | input('Enter to quit...') 43 | sys.exit() 44 | 45 | 46 | def __get_words(word, D_List): 47 | if word.upper() in D_List: 48 | return word.upper() 49 | else: 50 | Word_List=[i for i in D_List if i[0].upper()==word[0].upper()] 51 | Matches={} 52 | 53 | for test_word in Word_List: 54 | ratio=SM(None,test_word.upper(), word.upper()).ratio() 55 | if ratio>0.72: 56 | temp={test_word:round(ratio*100,2)} 57 | Matches.update(temp) 58 | 59 | val=list(Matches.values()) 60 | val.sort(reverse=1) 61 | val=val[:5] 62 | temp={} 63 | 64 | for j in val: 65 | for i in Matches: 66 | if Matches[i]==j: 67 | temp.update({i: j}) 68 | Matches=temp 69 | 70 | if len(Matches)==0: 71 | word=tj.color_text(word.upper(), text_color='YELLOW', 72 | bold=True, underline=True) 73 | print(f'\nWord your entered: {word}') 74 | print(f"{'-'*60}") 75 | print('No close matches were found, you might have entered a wrong word...') 76 | return None 77 | 78 | else: 79 | print(f'{word.upper()} was not found. We found {len(Matches)} close matches:') 80 | print('+-----------------------------+') 81 | print('| Word - Percent Match |') 82 | print('+-----------------------------+') 83 | j=0 84 | for i in Matches: 85 | j=j+1 86 | print('| %-16s - %-9s|' % ( i, f'{Matches[i]} %')) 87 | print('+-----------------------------+') 88 | best_match=list(Matches.keys())[0] 89 | print(f'\n**{best_match} ({Matches[best_match]} %) is the best match for the word - {word.upper()}') 90 | return best_match.upper() 91 | 92 | def print_meanings(word,data): 93 | print('WORD: ',word) 94 | MEANINGS=data['MEANINGS'] 95 | ANTONYMS=data['ANTONYMS'] 96 | SYNONYMS=data['SYNONYMS'] 97 | 98 | if SYNONYMS!=[]: 99 | SYNONYMS=', '.join(SYNONYMS) 100 | print('SYNONYMS: ',SYNONYMS) 101 | if ANTONYMS!=[]: 102 | ANTONYMS=', '.join(ANTONYMS) 103 | print('ANTONYMS: ',ANTONYMS) 104 | print('\n') 105 | 106 | L=[] 107 | j=0 108 | print(' -- MEANINGS --\n') 109 | to_print='\n NO MEANINGS AVAILABLE FOR THIS WORD' 110 | for sense_num in MEANINGS: 111 | template=f' * %s (%s) - %s\n%s%s' # word, t, m, c, e 112 | temp=MEANINGS[sense_num] 113 | t=temp[0] 114 | m=temp[1] 115 | c=temp[2] 116 | if c!=[]: 117 | c='\tIN CONTEXT WITH: '+'/ '.join(c) 118 | else: 119 | c='' 120 | 121 | 122 | e=temp[3] 123 | e=[f'{str(i)}. {e[i]}' for i in range(len(e))] 124 | if e!=[]: 125 | e='\n\tEXAMPLES :-\n\t\t'+'\n\t\t'.join(e) 126 | else: 127 | e='' 128 | L+=[template % (word, t, m, c, e)] 129 | to_print=f'\n\n'.join(L) 130 | j+=1 131 | if j%2==0: 132 | print(to_print) 133 | to_print='' 134 | L=[] 135 | choice=tj.instant_input().upper() 136 | if choice=='Q': 137 | return None 138 | print(to_print) 139 | 140 | 141 | 142 | def search_word(word): 143 | global D_List, D 144 | 145 | letter=word[0].upper() 146 | 147 | try: 148 | f=open(f'data\\D{letter}.json') 149 | data=f.read() 150 | D=json.loads(data) 151 | f.close() 152 | D_List=D.keys() 153 | except: 154 | print('The database is either corrupt or not present...') 155 | print('Downloading the data from online database (around 3.1 MB)..') 156 | setter() 157 | f=open(f'data\\D{letter}.json') 158 | data=f.read() 159 | D=json.loads(data) 160 | f.close() 161 | D_List=D.keys() 162 | 163 | 164 | word=__get_words(word, D_List) 165 | if word!=None: 166 | data=D[word] 167 | print_meanings(word, data) 168 | 169 | 170 | def add_new_word(): 171 | word=input('Enter the new word: ').upper() 172 | letter=word[0].upper() 173 | 174 | try: 175 | f=open(f'data\\D{letter}.json') 176 | D=f.read() 177 | D=json.loads(D) 178 | f.close() 179 | except: 180 | print('The database appears to be corrupt...') 181 | print('Downloading the data from online database (around 3.1 MB)...') 182 | setter() 183 | f=open(f'data\\D{letter}.json') 184 | D=f.read() 185 | D=json.loads(D) 186 | f.close() 187 | 188 | ANTONYMS=input('Enter antonyms for this word, seperated by a comma:- \n>>>').split(',') 189 | ANTONYMS=[i.strip().capitalize() for i in ANTONYMS] 190 | 191 | SYNONYMS=input('Enter synonyms for this word, seperated by a comma:- \n>>>').split(',') 192 | SYNONYMS=[i.strip().capitalize() for i in SYNONYMS] 193 | 194 | MEANINGS={} 195 | i=0 196 | print('YOU CAN PRESS ENTER TO SKIP, AND PRESS Q TO QUIT IN ANY OF THESE FIELDS-') 197 | while True: 198 | i+=1 199 | print('-'*40,'\n') 200 | 201 | m=input(f'Enter the meaning of this word-\nm{i}>>>') 202 | if m.upper()=='Q':break 203 | t=input(f'Enter the type of this word (Noun/ Verb/ Adverb, etc...)-\nt{i}>>>').capitalize() 204 | if t.upper()=='Q':break 205 | c=input(f'Enter the context of this meaning, seperated by / (Action/ Person/ Material etc...)-\nc{i}>>>') 206 | if c.upper()=='Q':break 207 | elif c=='':c=[] 208 | else:c=c.split('/') 209 | e=input(f'Enter an example to understand well, for multiple examples, add | to seperate examples-\ne{i}>>>') 210 | if e.upper()=='Q':break 211 | elif e=='':e=[] 212 | else:e=e.split('|') 213 | 214 | temp={i:[t,m,c,e]} 215 | MEANINGS.update(temp) 216 | 217 | D_word={word:{'MEANINGS':MEANINGS,'ANTONYMS':ANTONYMS, 'SYNONYMS':SYNONYMS}} 218 | D.update(D_word) 219 | 220 | f=open(f'data\\D{letter}.json','w') 221 | D=json.dumps(D) 222 | f.write(D) 223 | f.close() 224 | 225 | print('Word added successfully...') 226 | 227 | return word --------------------------------------------------------------------------------