فهرست منبع

feat: 爬取高中英语单词

SongZihuan 3 سال پیش
کامیت
576ee902ab
15فایلهای تغییر یافته به همراه4182 افزوده شده و 0 حذف شده
  1. 144 0
      .gitignore
  2. 3 0
      README.md
  3. 310 0
      db.py
  4. BIN
      global-dict.db
  5. BIN
      noto/NotoSansSC-Black.otf
  6. BIN
      noto/NotoSansSC-Bold.otf
  7. BIN
      noto/NotoSansSC-Light.otf
  8. BIN
      noto/NotoSansSC-Medium.otf
  9. BIN
      noto/NotoSansSC-Regular.otf
  10. BIN
      noto/NotoSansSC-Thin.otf
  11. 93 0
      noto/OFL.txt
  12. 3156 0
      resource/English-Word.txt
  13. 121 0
      tktool.py
  14. 208 0
      ui.py
  15. 147 0
      word.py

+ 144 - 0
.gitignore

@@ -0,0 +1,144 @@
+.idea
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+proarchive_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+etc
+*.xlsx
+Eglish-Word-Base.txt

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# H-English-Learn
+## 前言
+一个来自高中生的英语学习项目

+ 310 - 0
db.py

@@ -0,0 +1,310 @@
+import sqlite3
+import threading
+from typing import Optional, Union, List, Tuple, Dict
+import traceback
+
+import pandas
+import pandas as pd
+
+import word
+import re
+
+
+class DataBase:
+    def __init__(self, name):
+        self._db = sqlite3.connect(f"{name}.db")
+        self._cursor = self._db.cursor()
+        self._lock = threading.RLock()
+
+    def get_cursor(self) -> sqlite3.Cursor:
+        return self._cursor
+
+    def search(self, columns: List[str], table: str,
+               where: Union[str, List[str]] = None,
+               limit: Optional[int] = None,
+               offset: Optional[int] = None,
+               order_by: Optional[List[Tuple[str, str]]] = None,
+               group_by: Optional[List[str]] = None,
+               for_update: bool = False):
+        if type(where) is list and len(where) > 0:
+            where: str = " WHERE " + " AND ".join(f"({w})" for w in where)
+        elif type(where) is str and len(where) > 0:
+            where = " WHERE " + where
+        else:
+            where: str = ""
+
+        if order_by is None:
+            order_by: str = ""
+        else:
+            by = [f" {i[0]} {i[1]} " for i in order_by]
+            order_by: str = " ORDER BY" + ", ".join(by)
+
+        if limit is None or limit == 0:
+            limit: str = ""
+        else:
+            limit = f" LIMIT {limit}"
+
+        if offset is None:
+            offset: str = ""
+        else:
+            offset = f" OFFSET {offset}"
+
+        if group_by is None:
+            group_by: str = ""
+        else:
+            group_by = "GROUP BY " + ", ".join(group_by)
+
+        columns: str = ", ".join(columns)
+        if for_update:
+            for_update = "FOR UPDATE"
+        else:
+            for_update = ""
+        return self.__search(f"SELECT {columns} "
+                             f"FROM {table} "
+                             f"{where} {group_by} {order_by} {limit} {offset} {for_update};")
+
+    def insert(self, table: str, columns: list, values: Union[str, List[str]], not_commit: bool = False):
+        columns: str = ", ".join(columns)
+        if type(values) is str:
+            values: str = f"({values})"
+        else:
+            values: str = ", ".join(f"{v}" for v in values)
+        return self.done(f"INSERT INTO {table}({columns}) VALUES {values};", not_commit=not_commit)
+
+    def delete(self, table: str, where: Union[str, List[str]] = None, not_commit: bool = False):
+        if type(where) is list and len(where) > 0:
+            where: str = " AND ".join(f"({w})" for w in where)
+        elif type(where) is not str or len(where) == 0:  # 必须指定条件
+            return None
+
+        return self.done(f"DELETE FROM {table} WHERE {where};", not_commit=not_commit)
+
+    def update(self, table: str, kw: "Dict[str:str]", where: Union[str, List[str]] = None,
+               not_commit: bool = False):
+        if len(kw) == 0:
+            return None
+
+        if type(where) is list and len(where) > 0:
+            where: str = " AND ".join(f"({w})" for w in where)
+        elif type(where) is not str or len(where) == 0:  # 必须指定条件
+            return None
+
+        kw_list = [f"{key} = {kw[key]}" for key in kw]
+        kw_str = ", ".join(kw_list)
+        return self.done(f"UPDATE {table} SET {kw_str} WHERE {where};", not_commit=not_commit)
+
+    def __search(self, sql) -> Union[None, sqlite3.Cursor]:
+        try:
+            self._lock.acquire()  # 上锁
+            self._cursor.execute(sql)
+        except sqlite3.Error:
+            traceback.print_exc()
+            print(f"sql='{sql}'")
+            return None
+        finally:
+            self._lock.release()  # 释放锁
+        return self._cursor
+
+    def done(self, sql, not_commit: bool = False) -> Union[None, sqlite3.Cursor]:
+        try:
+            self._lock.acquire()
+            self._cursor.execute(sql)
+        except sqlite3.Error:
+            self._db.rollback()
+            print(f"sql={sql}")
+            traceback.print_exc()
+            return None
+        finally:
+            if not not_commit:
+                self._db.commit()
+            self._lock.release()
+        return self._cursor
+
+    def commit(self):
+        try:
+            self._lock.acquire()
+            self._db.commit()
+        finally:
+            self._lock.release()
+
+
+class WordDatabase(DataBase):
+    word_pattern = re.compile("([a-zA-Z\']+)")  # 匹配英语单词
+
+    def __init__(self, dict_name: str = "global"):
+        super(WordDatabase, self).__init__(dict_name + "-dict")
+        self.dict_name = dict_name
+        self.done(f'''
+        CREATE TABLE IF NOT EXISTS Word (
+            id INTEGER PRIMARY KEY AUTOINCREMENT,  -- 编码
+            box INTEGER NOT NULL DEFAULT 1 CHECK (box < 6 and box > 0),
+            word TEXT NOT NULL,  -- 单词
+            part TEXT NOT NULL,  -- 词性
+            english TEXT NOT NULL,  -- 英文注释
+            chinese TEXT NOT NULL,  -- 中文注释
+            eg TEXT  -- 例句
+        )''')
+        self.wd = word.WordDict()
+
+    def find_word(self, q: str) -> Optional[word.Word]:
+        cur = self.search(columns=["id", "word", "part", "english", "chinese", "eg"],
+                          table="Word",
+                          where=f"LOWER(word)='{q.lower()}'")
+        res = []
+        if cur is not None:
+            res = cur.fetchall()
+
+        if len(res) <= 0:
+            r = self.wd.get_requests(q)
+            if not r.is_find:
+                return None
+            ret = None
+            for i in r.res:
+                w = r.res[i]
+                if ret is None:
+                    ret = w
+                name = w.name
+                name_lower = name.lower().replace("'", "''")
+                cur = self.search(columns=["word"], table="Word", where=f"LOWER(word)='{name_lower}'")
+                if cur is not None and len(cur.fetchall()) > 0:
+                    continue
+                for c in w.comment:
+                    comment = r.res[i].comment[c]
+                    eg = '@@'.join(comment.eg).replace("'", "''")
+                    part = comment.part.replace("'", "''")
+                    english = comment.english.replace("'", "''")
+                    chinese = comment.chinese.replace("'", "''")
+                    self.insert(table='Word',
+                                columns=['word', 'part', 'english', 'chinese', 'eg'],
+                                values=f"'{name_lower}', '{part}', '{english}', '{chinese}', '{eg} '")
+            return ret
+
+        w = word.Word(q)
+        for i in res:
+            c = word.Word.Comment(i[2], i[3], i[4])
+            for e in i[5].split("@@"):
+                c.add_eg(e)
+            w.add_comment(c)
+        return w
+
+    def delete_word(self, q: str):
+        self.delete(table="Word", where=f"LOWER(word)='{q.lower()}'")
+
+    def delete_all(self):
+        self.delete(table="Word")
+
+    class UpdateResponse:
+        def __init__(self):
+            self._success = 0
+            self._error = 0
+            self._error_list = []
+
+        def add_success(self):
+            self._success += 1
+
+        def add_error(self, q: str):
+            self._error += 1
+            self._error_list.append(q)
+            print(f"Error: {q}")
+
+        def response(self):
+            return self._success, self._error, self._error_list
+
+    def update_from_txt(self, file: str):
+        response = self.UpdateResponse()
+        with open(file, encoding='utf-8') as f:
+            for i in f.readlines():
+                word_list = self.word_pattern.findall(i)
+                for w in word_list:
+                    try:
+                        if self.find_word(w) is None:
+                            response.add_error(w)
+                        else:
+                            response.add_success()
+                    except:
+                        response.add_error(w)
+                        traceback.print_exc()
+        return True, response
+
+    def update_from_table(self, file: str, t: str = 'csv'):
+        if t == 'txt':
+            return self.update_from_txt(file)
+        elif t == 'csv':
+            df = pd.read_csv(file, encoding='utf-8')
+        elif t == 'excel':
+            df = pd.read_excel(file, encoding='utf-8')
+        elif t == 'json':
+            df = pd.read_json(file, encoding='utf-8')
+        else:
+            return False, []
+
+        response = self.UpdateResponse()
+        for i in df.itertuples():
+            try:
+                if self.find_word(str(i[0])) is None:
+                    response.add_error(str(i[0]))
+                else:
+                    response.add_success()
+            except:
+                response.add_error(str(i[0]))
+                traceback.print_exc()
+        return True, response
+
+    def export_as_txt(self, file: str):
+        cur = self.search(columns=["word"],
+                          table="Word",
+                          order_by=[('box', 'DESC')])
+        if cur is None:
+            return False
+        res = cur.fetchall()
+        export = []
+        with open(file + '.txt', encoding='utf-8', mode="w") as f:
+            for i in res:
+                if i[0] in export:
+                    continue
+                f.write(i[0] + '\n')
+                export.append(i[0])
+        return True
+
+    def export_as_table(self, file: str, t: str = 'excel'):
+        if t == 'txt':
+            return self.export_as_txt(file)
+
+        cur = self.search(columns=["box", "word", "part", "english", "chinese", "eg"],
+                          table="Word",
+                          order_by=[('box', 'DESC')])
+        if cur is None:
+            return False
+        res = cur.fetchall()
+        df = pandas.DataFrame(columns=["Box", "Word", "Part", "English", "Chinese", "Eg"])
+        export = []
+        for i in res:
+            if i[1] in export:
+                continue
+            export.append(i[1])
+            eg = i[5].split("@@")
+            eg_str = ""
+            for e in eg:
+                ec = e.split("##")
+                if len(ec) == 2:
+                    eng, chi = ec
+                else:
+                    eng = ec[0]
+                    chi = ""
+                if len(eng.replace(" ", "")) == 0:
+                    continue
+                eg_str += f"{eng} ({chi})\n"
+            df = df.append({"Box": str(i[0]),
+                            "Word": str(i[1]),
+                            "Part": str(i[2]),
+                            "English": str(i[3]),
+                            "Chinese": str(i[4]),
+                            "Eg": eg_str}, ignore_index=True)
+        if t == 'csv':
+            df.to_csv(file + ".csv", encoding='utf-8')
+        elif t == 'excel':
+            df.to_excel(file + ".xlsx", encoding='utf-8')
+        elif t == 'json':
+            df.to_json(file + ".json", encoding='utf-8')
+        else:
+            return False

BIN
global-dict.db


BIN
noto/NotoSansSC-Black.otf


BIN
noto/NotoSansSC-Bold.otf


BIN
noto/NotoSansSC-Light.otf


BIN
noto/NotoSansSC-Medium.otf


BIN
noto/NotoSansSC-Regular.otf


BIN
noto/NotoSansSC-Thin.otf


+ 93 - 0
noto/OFL.txt

@@ -0,0 +1,93 @@
+Copyright 2012 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.

+ 3156 - 0
resource/English-Word.txt

@@ -0,0 +1,3156 @@
+addict
+accent
+accept
+addition
+access
+address
+adjust
+accident
+accommodation
+administration
+accompany
+admire
+accord
+to
+admit
+account
+adopt
+adorable
+accurate
+accuse
+adult
+ache
+advance
+achieve
+advantage
+achievement
+adventure
+acid
+advertise
+acknowledge
+advertisement
+ad
+acquire
+advice
+across
+advise
+act
+advocate
+action
+affair
+active
+affect
+activity
+afford
+actor
+afraid
+actress
+africa
+actually
+african
+adapt
+after
+after-
+afternoon
+adaptation
+afterwards
+add
+again
+against
+age
+-age
+always
+agency
+agenda
+amateur
+ago
+amazing
+agree
+ambition
+agreement
+ambitious
+agriculture
+ambulance
+ahead
+america
+aid
+american
+aim
+among
+air
+amount
+amuse
+airline
+airport
+analyse
+analyze
+alarm
+ancestor
+alcohol
+ancient
+alive
+and
+anger
+all
+all-
+allow
+angle
+almost
+angry
+alone
+animal
+along
+alongside
+announce
+aloud
+annoy
+already
+annual
+also
+another
+alternative
+answer
+although
+ant
+-ant
+antique
+anticipate
+april
+arch
+arch-
+anxiety
+architect
+anxious
+area
+any
+anybody
+argue
+anyhow
+arm
+arise
+anyone
+army
+anything
+around
+anyway
+arrangement
+anywhere
+arrest
+arrive
+apartment
+arrow
+apologize
+art
+apparently
+article
+appeal
+artificial
+appear
+artist
+appetite
+applaud
+as
+ashamed
+apple
+asia
+applicant
+asian
+application
+apply
+aside
+ask
+appointment
+asleep
+appreciate
+approach
+aspect
+appropriate
+assess
+approve
+assign
+assistant
+available
+association
+average
+assume
+avoid
+assumption
+awake
+astonish
+award
+astronaut
+aware
+astronomer
+at
+away
+awesome
+athlete
+awful
+atmosphere
+awkward
+attach
+b
+b.
+attack
+baby
+attain
+attempt
+back
+background
+attend
+attention
+backward
+attitude
+bacon
+attract
+bad
+audience
+badminton
+august
+bag
+aunt
+bakery
+australia
+balance
+australian
+ball
+author
+ballet
+authority
+balloon
+automatic
+bamboo
+autonomous
+ban
+banana
+autumn
+band
+bank
+beautiful
+bar
+the bar
+beauty
+barbecue
+because
+barely
+become
+bark
+bed
+barrier
+bedroom
+base
+beef
+baseball
+beer
+before
+basic
+begin
+basis
+basin
+behalf
+behave
+basket
+behaviour
+basketball
+behind
+bat
+bath
+being
+belief
+bathroom
+believe
+battery
+bell
+battle
+belong
+bay
+below
+bc
+belt
+beach
+be
+am
+a.m.
+are
+is
+bend
+beneath
+bean
+benefit
+curd
+tofu
+beside
+bear
+best
+beard
+bet
+beat
+better
+between
+board
+beyond
+big
+boat
+body
+bill
+the bill
+bike
+bicycle
+boil
+bomb
+billion
+d, d
+bond
+bird
+biology
+bone
+birth
+bonus
+book
+birthday
+boost
+biscuit
+boot
+bit
+border
+bite
+bored
+bitter
+boring
+black
+born
+-born
+blackboard
+borrow
+blame
+boss
+blank
+botanical
+blanket
+both
+bleed
+bother
+bless
+bottle
+blind
+bottom
+block
+bounce
+bound
+-bound
+blood
+boundary
+blouse
+bow
+blow
+bowl
+blue
+bowling
+box
+buffet
+boxing
+build
+boy
+building
+brain
+bunch
+branch
+burn
+brave
+bury
+bread
+bus
+break
+business
+breakfast
+busy
+breath
+breast
+but
+butcher
+breathe
+butter
+brick
+button
+bride
+bridegroom
+buy
+bridge
+by
+bright
+c.
+c++
+brilliant
+cabbage
+bring
+café
+britain
+cafeteria
+british
+broad
+cake
+cage
+broadcast
+calculate
+brochure
+calendar
+brother
+brown
+call
+calligraphy
+brush
+calm
+budget
+the budget
+calorie
+camel
+camera
+camp
+carrot
+campaign
+carry
+campus
+can
+carve
+canada
+case
+canadian
+cash
+cancel
+canal
+cast
+castle
+cancer
+cat
+candidate
+catch
+candle
+category
+candy
+canteen
+cause
+cap
+cave
+capable
+-capable
+cease
+ceiling
+capacity
+celebrate
+capital
+capsule
+celebrity
+captain
+cell
+cent
+centimetre
+car
+carbon
+central
+card
+centre
+center
+care
+century
+career
+certain
+careful
+certainly
+careless
+certificate
+chain
+chair
+chairwoman
+chicken
+chew
+chalk
+challenge
+child
+pl.
+champion
+chance
+china
+change
+channel
+chinese
+chaos
+chocolate
+chapter
+choice
+character
+choke
+characteristic
+charity
+charge
+chorus
+christmas
+chopstick
+chart
+chat
+church
+cheap
+cinema
+cigarette
+s
+'s
+-s
+-s'
+-'s
+cheat
+check
+circle
+cheek
+circuit
+circumstance
+cheer
+cheese
+circus
+chef
+cite
+citizen
+chemical
+city
+chemist
+civil
+chemistry
+civilian
+chess
+civilization
+coast
+claim
+clap
+coat
+coffee
+clarify
+class
+coin
+cold
+classic
+classmate
+collapse
+classroom
+collar
+collect
+clean
+collection
+clear
+college
+colour
+color
+clerk
+clever
+column
+combine
+click
+client
+come
+comedy
+climate
+climb
+comfort
+clinic
+comfortable
+comic
+clone
+comment
+close
+commercial
+commit
+cloth
+clothes
+commitment
+cloud
+committee
+cloudy
+common
+club
+communicate
+clue
+communication
+coach
+coal
+community
+company
+confirm
+compare
+comparison
+confucianism
+compete
+confucius
+competence
+confused
+competition
+congratulation
+complain
+connect
+complete
+complex
+conservation
+complicated
+consider
+component
+compose
+consistent
+composition
+constant
+comprehension
+constitution
+comprehensive
+construction
+comprise
+consultant
+computer
+consultation
+concentrate
+consume
+concept
+consumption
+concern
+contact
+concert
+contain
+conclude
+contemporary
+conclusion
+content
+concrete
+contest
+condition
+context
+conduct
+continent
+the continent
+conference
+continue
+confidence
+contract
+contradictory
+country
+contrary
+countryside
+county
+contrast
+contribution
+couple
+courage
+control
+convenient
+course
+court
+conventional
+cousin
+conversation
+cover
+convince
+cook
+coverage
+cookie
+cow
+crash
+cool
+crayon
+cooperate
+copy
+crazy
+cream
+core
+corn
+create
+comer
+creative
+creature
+corporate
+correct
+credit
+crew
+correspond
+cost
+crime
+crisis
+costume
+cottage
+criterion
+critical
+cotton
+cough
+criticize
+could
+crop
+council
+cross
+cross-
+crowd
+crucial
+date
+cry
+daughter
+cuisine
+day
+culture
+dead
+deadline
+cup
+cupboard
+deaf
+cure
+deal
+dear
+curious
+death
+current
+debate
+curtain
+debt
+custom
+custom-
+decade
+customer
+december
+cut
+decent
+cute
+decide
+cycle
+decision
+declare
+d.
+'d
+decline
+daily
+decorate
+damage
+decrease
+damp
+deep
+dance
+deer
+danger
+defeat
+dangerous
+defence
+defense
+dare
+defend
+dark
+definitely
+data
+definition
+degree
+-degree
+database
+delay
+delete
+detective
+determine
+delicate
+develop
+delicious
+development
+device
+deliver
+demand
+demonstrate
+diagram
+dentist
+dialogue
+dialog box
+deny
+diamond
+department
+diary
+departure
+dictionary
+depend
+die
+depress
+diet
+depth
+differ
+describe
+difference
+description
+different
+desert
+difficult
+deserve
+difficulty
+design
+dig
+desire
+digest
+digital
+desk
+desperate
+dignity
+despite
+dimension
+dessert
+dine
+destination
+dinner
+destroy
+dinosaur
+detail
+direct
+detect
+direction
+director
+diverse
+directory
+divide
+dirty
+division
+disabled
+disability
+dizzy
+disappointed
+document
+disaster
+dog
+discipline
+dollar
+discount
+dolphin
+discover
+domain
+discovery
+domestic
+discrimination
+dominate
+discuss
+donate
+discussion
+door
+disease
+dormitory
+dish
+double
+disk
+disc
+doubt
+dismiss
+down
+down-
+display
+download
+distance
+downstairs
+distant
+downtown
+distinct
+dozen
+distinguish
+draft
+distribution
+drag
+district
+dragon
+disturb
+drama
+dive
+dramatic
+draw
+drawer
+earn
+dream
+earth
+earthquake
+dress
+drill
+ease
+drink
+east
+drive
+eastern
+driver
+easy
+eat
+drop
+drought
+ecology
+drug
+economic
+edge
+dry
+editor
+duck
+education
+due
+educator
+dumpling
+effect
+duration
+efficient
+during
+effort
+dust
+egg
+duty
+eight
+dynamic
+eighteen
+dynasty
+eighth
+eighty
+e, e
+either
+each
+elder
+eager
+elderly
+eagle
+election
+ear
+electricity
+early
+electronic
+treatment
+typhoon
+typical
+tree
+trial
+trend
+u, u
+ugly
+trick
+the uk
+trip
+trouble
+ultimately
+trousers
+umbrella
+truck
+uncle
+true
+under
+under-
+trunk
+underground
+trust
+understand
+truth
+uniform
+try
+unique
+t, t
+shirt
+unit
+universe
+tube
+tuesday
+university
+tune
+unless
+turkey
+until
+till
+turn
+unusual
+twelfth
+twelve
+update
+twentieth
+upon
+twenty
+twice
+twin
+upper
+upset
+urban
+two
+type
+urge
+urgent
+us
+the us
+village
+violence
+use
+violin
+used
+virtual
+useful
+virtue
+usual
+virus
+usually
+visible
+vision
+v
+visit
+vacation
+visitor
+valley
+visual
+valuable
+vital
+value
+vivid
+variation
+vocabulary
+variety
+voice
+various
+volcano
+volleyball
+vary
+vase
+volume
+vast
+volunteer
+vegetable
+vote
+vehicle
+venue
+w, w
+version
+wage
+very
+waist
+victim
+wait
+victory
+wake
+video
+walk
+view
+wall
+elegant
+enjoy
+element
+enormous
+elephant
+enough
+eleven
+ensure
+else
+enter
+elsewhere
+enterprise
+email
+entertainment
+embarrassed
+enthusiastic
+emerge
+entirely
+emergency
+entitle
+emotion
+entrance
+emperor
+emphasis
+entry
+envelope
+employ
+environment
+empty
+envy
+encounter
+episode
+equal
+encourage
+equator
+end
+equipment
+enemy
+energetic
+eraser
+error
+engage
+engagé
+engine
+erupt
+escape
+engineer
+especially
+england
+essay
+english
+essential
+enhance
+establish
+estate
+excuse
+estimate
+exercise
+europe
+exhibition
+european
+exist
+evaluate
+eve
+exit
+expand
+even
+expansion
+event
+evening
+expect
+expectation
+eventually
+expense
+ever
+expensive
+every
+experience
+everybody
+experiment
+everyday
+expert
+everyone
+explain
+everything
+explode
+everywhere
+explore
+evidence
+export
+expose
+exposé
+exactly
+exam
+examination
+exposure
+examine
+express
+extend
+example
+extension
+excellent
+except
+extent
+exceptional
+external
+exchange
+extinction
+extra
+extra-
+extraordinary
+excited
+exciting
+extremely
+fast
+eye
+fat
+f, f
+father
+dad
+fault
+fabric
+favour
+favor
+face
+favourite
+favorite
+facilitate
+fear
+facility
+feature
+fact
+february
+factor
+fee
+factory
+feed
+fail
+feel
+failure
+feeling
+fair
+fellow
+faith
+female
+fall
+fence
+false
+festival
+familiar
+fetch
+family
+fever
+famous
+few
+fan
+fibre
+fiber
+fancy
+fiction
+fantastic
+field
+-field
+fantasy
+far
+fifth
+farm
+fifty
+farmer
+fight
+fashion
+figure
+file
+fill
+flour
+flow
+film
+flower
+finally
+finance
+flu
+fluent
+financial
+find
+fly
+focus
+finding
+foggy
+fine
+fold
+-fold
+finger
+folk
+finish
+follow
+fire
+fond
+firm
+food
+first
+foot
+feet
+fish
+football
+fisherman
+for
+fist
+force
+fit
+forecast
+five
+forehead
+fix
+foreign
+forest
+flag
+flash
+forever
+forget
+flat
+flavour
+flavor
+forgive
+flexible
+fork
+form
+flight
+formal
+flood
+format
+floor
+former
+-former
+from
+fortunately
+front
+forty
+frontier
+forward
+frost
+found
+fruit
+foundation
+fry
+fountain
+fuel
+four
+full
+fourteen
+fun
+fourth
+function
+fox
+fund
+france
+fundamental
+frank
+funny
+free
+-free
+furniture
+freedom
+further
+freeze
+future
+french
+g
+frequency
+frequently
+gain
+fresh
+fresh-
+gallery
+friction
+game
+friday
+gap
+fridge
+refrigerator
+garbage
+friend
+garden
+friendly
+-friendly
+garlic
+friendship
+gas
+frightened
+frog
+gate
+-gate
+gather
+gender
+general
+gold
+golf
+generate
+generation
+good
+goodbye
+bye
+generous
+genius
+government
+gentle
+gentleman
+grab
+grade
+gradually
+genuine
+geography
+graduate
+grain
+geometry
+german
+grammar
+germany
+gramme
+gram
+grand
+get
+gift
+granddaughter
+gifted
+grandfather
+grandpa
+giraffe
+grandmother
+grandma
+girl
+grandparent
+give
+grandson
+glad
+grape
+grasp
+glass
+global
+grass
+globe
+grateful
+gravity
+glove
+great
+great-
+glue
+greedy
+go
+goal
+green
+goat
+greenhouse
+greet
+hand
+grey
+handbag
+grocery
+handkerchief
+ground
+handle
+group
+handsome
+grow
+handwriting
+guarantee
+hang
+guard
+the guard
+happen
+guess
+happy
+guest
+hard
+guidance
+hardly
+guide
+harm
+guideline
+harmful
+guilty
+harmonious
+guitar
+harmony
+gun
+guy
+harvest
+hat
+gym
+hatch
+gymnastics
+hate
+have
+has
+h, h
+he
+habit
+head
+-head
+habitat
+headache
+hair
+health
+half
+healthy
+hall
+hear
+ham
+heart
+hamburger
+heat
+heavy
+height
+hold
+hello
+hole
+holiday
+help
+home
+helpful
+hometown
+hen
+homework
+hence
+honest
+her
+herb
+honey
+honour
+honor
+here
+hope
+hero
+horrible
+horse
+herself
+hospital
+hesitate
+host
+hot
+hide
+hotel
+high
+hour
+highlight
+house
+hike
+hill
+him
+housing
+himself
+how
+hire
+however
+hug
+his
+huge
+historic
+human
+history
+hit
+humble
+humorous
+hobby
+hundred
+impact
+imply
+hungry
+-hungry
+hunt
+import
+hurricane
+important
+impossible
+hurry
+hurt
+impress
+husband
+impression
+hydrogen
+improve
+in
+in.
+in-
+-in
+inch
+incident
+ice
+include
+income
+idea
+increase
+ideal
+incredible
+identical
+indeed
+identify
+independent
+identity
+india
+idiom
+indian
+indicate
+ignore
+individual
+ill
+ill-
+i'll
+industry
+illegal
+infection
+illness
+infer
+illustrate
+influence
+image
+influential
+imagine
+information
+immediately
+initial
+initiative
+interest
+injury
+interesting
+inner
+innocent
+internal
+international
+innovation
+the internet
+input
+inquire
+interpret
+insect
+interrupt
+non-intervention
+inside
+interview
+insight
+into
+introduce
+insist
+inspection
+introduction
+inspire
+invent
+instance
+invention
+instant
+investigate
+instead
+investment
+institute
+invite
+institution
+involve
+iron
+instruction
+instrument
+island
+insurance
+issue
+integrate
+it
+it-
+integrity
+item
+its
+it's
+intelligent
+itself
+intend
+intense
+intention
+interaction
+jacket
+jam
+k, k
+january
+japan
+kangaroo
+japanese
+keep
+jazz
+key
+kettle
+jaw
+jeans
+keyboard
+job
+kick
+jog
+kid
+join
+kill
+joint
+kilo
+kilo-
+joke
+kilogram
+journal
+kilometre
+journalist
+kind
+kindergarten
+joy
+king
+judge
+kingdom
+juice
+kiss
+july
+kit
+jump
+kitchen
+june
+kite
+jungle
+knee
+junior
+knife
+just
+knock
+justice
+know
+justify
+knowledge
+l
+leadership
+lab
+lab.
+laboratory
+leaf
+league
+label
+labour
+labor
+leak
+learn
+lack
+least
+lady
+leather
+lake
+leave
+lamb
+lecture
+lamp
+left
+land
+leg
+landscape
+legal
+language
+leisure
+lantern
+lemon
+lap
+lend
+length
+-length
+laptop
+large
+less
+-less
+last
+lesson
+late
+let
+-let
+letter
+later
+level
+launch
+liberation
+liberty
+law
+lawyer
+librarian
+library
+lay
+license
+lazy
+lie
+lead
+life
+leader
+lift
+lonely
+light
+long
+long.
+like
+-like
+look
+likely
+limit
+lose
+loose
+limited
+loss
+line
+lot
+link
+loud
+lion
+love
+liquid
+lovely
+list
+low
+listen
+lower
+literally
+luck
+literary
+lucky
+literature
+lunar
+litter
+lunch
+little
+lung
+live
+luxury
+lively
+living
+m
+'m
+load
+-load
+machine
+loan
+mad
+-mad
+local
+madam
+location
+magazine
+lock
+magic
+log
+mail
+logical
+main
+london
+maintain
+major
+may
+majority
+maybe
+make
+me
+male
+meal
+man
+-man
+men
+manage
+meaning
+manager
+mankind
+means
+measure
+meat
+manner
+many
+mechanic
+map
+medal
+marathon
+medical
+march
+medicine
+medium
+media
+mark
+meet
+market
+meeting
+marriage
+member
+marry
+membership
+mass
+memorial
+massive
+memory
+master
+mental
+mention
+match
+material
+menu
+mercy
+maths
+mathematics
+merely
+matter
+mature
+merry
+maximum
+mess
+message
+metal
+mistake
+method
+mix
+metre
+meter
+mixture
+microscope
+mobile
+phone
+mode
+middle
+midnight
+model
+might
+modern
+mild
+moment
+mile
+monday
+military
+money
+milk
+monitor
+millimetre
+monkey
+million
+month
+mind
+monthly
+mine
+mineral
+mood
+moon
+minimum
+moral
+minister
+more
+minor
+moreover
+minority
+morning
+minute
+mosquito
+mirror
+most
+-most
+miss
+mostly
+mother
+mum
+missile
+motion
+missing
+motivate
+mission
+mist
+motive
+motor
+mount
+national
+mountain
+mouse
+mice
+nationality
+native
+mouth
+natural
+move
+nature
+movement
+movie
+navy
+near
+near-
+mr
+nearby
+mrs
+nearly
+ms
+much
+neat
+necessary
+mud
+neck
+need
+multiple
+needle
+murder
+negative
+muscle
+negotiate
+museum
+mushroom
+neighbour
+music
+neighbourhood
+musician
+neither
+must
+must-
+nephew
+my
+nervous
+nest
+myself
+net
+the net
+.net
+network
+n
+'n'
+nail
+never
+nevertheless
+name
+new
+new-
+narrow
+news
+nation
+novel
+newspaper
+next
+novelist
+nice
+november
+niece
+now
+night
+nowadays
+nine
+nowhere
+nineteen
+nuclear
+ninety
+number
+ninth
+nurse
+no
+no.
+nut
+noble
+nutrition
+nobody
+nod
+noise
+object
+noisy
+objective
+none
+observe
+noodle
+obtain
+noon
+obviously
+nor
+occasion
+occupation
+north
+occupy
+northern
+occur
+nose
+ocean
+note
+october
+notebook
+odd
+-odd
+nothing
+of
+notice
+off
+normal
+offer
+orange
+office
+officer
+orbit
+official
+order
+ordinary
+often
+organ
+oil
+organic
+ok
+non-governmental organization
+organization
+old
+the olympics
+origin
+original
+on
+other
+once
+otherwise
+one
+onion
+ought to
+our
+online
+ours
+only
+ourselves
+onto
+out
+out-
+open
+outcome
+outgoing
+opera
+operation
+outline
+operator
+output
+opinion
+outside
+opponent
+outstanding
+opportunity
+over
+over-
+overall
+oppose
+overcome
+opposite
+optimistic
+overseas
+owe
+option
+own
+or
+oxygen
+party
+p
+p.
+pass
+passage
+pace
+pacific
+passenger
+passion
+the passion
+pack
+-pack
+package
+passive
+page
+passport
+past
+pain
+paint
+patent
+path
+pair
+palace
+the palace
+patience
+pale
+patient
+pan
+pan-
+pattern
+pancake
+pay
+panda
+pe
+physical
+panel
+peace
+panic
+peak
+paper
+pear
+paragraph
+pen
+parcel
+pencil
+pardon
+people
+park
+parent
+pepper
+parking
+per
+perceive
+part
+percent
+participate
+percentage
+particular
+perfect
+performance
+perhaps
+pill
+pilot
+period
+permanent
+pink
+pioneer
+permit
+person
+-person
+pipe
+personal
+pity
+personality
+place
+persuade
+plain
+plan
+pessimistic
+plane
+pet
+planet
+petrol
+plant
+plastic
+phase
+phenomenon
+plate
+philosophy
+platform
+play
+photo
+photo-
+photograph
+player
+photographer
+playground
+phrase
+pleasant
+physician
+please
+physics
+pleasure
+piano
+plenty
+pick
+plug
+picnic
+plus
+picture
+pocket
+pie
+poem
+piece
+-piece
+pig
+poet
+poetry
+post
+post-
+postcard
+point
+poster
+poison
+postman
+pole
+polar
+postpone
+police
+potato
+policeman
+policewoman
+potential
+policy
+polish
+pound
+polite
+pour
+power
+political
+practical
+politician
+practice
+politics
+praise
+pollute
+pond
+pollution
+pray
+precious
+pool
+precisely
+predict
+poor
+prefer
+popular
+pop
+pop.
+preference
+population
+pork
+prejudice
+port
+premier
+prepare
+pose
+present
+position
+presentation
+positive
+possession
+president
+preserve
+possible
+press
+pressure
+programme
+program
+progress
+pretty
+prohibit
+prevent
+project
+previous
+promise
+price
+promote
+pride
+pronounce
+primary
+pronunciation
+primitive
+principle
+proof
+-proof
+proper
+print
+property
+prior
+priority
+proposal
+prison
+prospect
+protect
+private
+prize
+protein
+protest
+probably
+proud
+prove
+problem
+provide
+procedure
+province
+proceed
+process
+psychology
+pub
+produce
+product
+public
+profession
+publish
+professional
+pudding
+pull
+professor
+profile
+punish
+profit
+pupil
+purchase
+radio
+pure
+radium
+purple
+railway
+purpose
+rain
+purse
+pursue
+rainbow
+rainy
+push
+raise
+put
+random
+q, q
+range
+rank
+qualification
+rapid
+qualify
+quality
+rare
+rate
+-rate
+quantity
+rather
+quarter
+rating
+queen
+raw
+question
+quick
+reach
+ray
+quit
+quiet
+react
+reaction
+quite
+read
+quote
+ready
+real
+realize
+rabbit
+realistic
+race
+reality
+racial
+really
+radiation
+reason
+recall
+regular
+receipt
+receive
+reject
+relate
+recently
+relationship
+receptionist
+recipe
+relative
+relax
+recite
+relay
+recognize
+release
+recognition
+relevant
+recommend
+reliable
+record
+relief
+recording
+recover
+remain
+recreation
+remarkable
+recycle
+remember
+remind
+red
+remote
+reduce
+remove
+rent
+reference
+repair
+reflect
+repeat
+replace
+reform
+reply
+refresh
+report
+refuse
+represent
+regard
+representative
+regardless
+region
+reputation
+register
+regret
+request
+rhyme
+require
+rice
+rescue
+rich
+-rich
+research
+riddle
+reserve
+ride
+resident
+right
+resign
+resistance
+the resistance
+ring
+rigid
+resolution
+resolve
+ripe
+rise
+resource
+risk
+respect
+river
+respective
+road
+respond
+response
+roast
+robot
+responsibility
+rock
+responsible
+rocket
+rest
+role
+restaurant
+roll
+restore
+romantic
+restrict
+result
+room
+roof
+retire
+return
+rope
+root
+reveal
+rose
+rosé
+review
+round
+revise
+reward
+route
+routine
+row
+sand
+royal
+sandwich
+rubber
+rubbish
+satellite
+satisfaction
+rude
+satisfy
+rugby
+saturday
+ruin
+saucer
+rule
+sausage
+ruler
+save
+run
+saving
+-saving
+rural
+say
+rush
+saying
+russia
+scare
+russian
+scarf
+o, o
+scene
+schedule
+sad
+scholarship
+safe
+school
+safety
+schoolbag
+science
+sail
+salad
+scientific
+salary
+scientist
+scissors
+sale
+salesman
+saleswoman
+score
+scream
+salt
+salty
+screen
+sculpture
+same
+sea
+sample
+search
+serve
+season
+service
+seat
+-seat
+session
+second
+set
+secondary
+setting
+secret
+settle
+secretary
+seven
+section
+seventeen
+secure
+seventh
+security
+seventy
+see
+several
+seed
+seek
+severe
+sew
+seem
+sex
+seize
+shade
+seldom
+shadow
+select
+shake
+sell
+shall
+send
+shallow
+senior
+shame
+sense
+shape
+sensitive
+share
+sentence
+shark
+separate
+sharp
+september
+shave
+series
+she
+serious
+sheep
+sheet
+servant
+shelf
+shelter
+silent
+shift
+silk
+shine
+silly
+silver
+ship
+-ship
+similar
+simple
+shock
+since
+shoe
+sincerely
+shoot
+sing
+sing.
+shop
+single
+shore
+sink
+sir
+short
+short-
+shortage
+sister
+sit
+shorts
+should
+site
+shoulder
+situation
+shout
+six
+show
+sixth
+sixteen
+shower
+sixty
+shut
+size
+shy
+-shy
+skate
+sick
+skateboard
+side
+ski
+sight
+skill
+skin
+sign
+skip
+signal
+significant
+silence
+sky
+soft
+sleep
+software
+sleepy
+slice
+soil
+solar
+slide
+soldier
+slightly
+solid
+solution
+slip
+solve
+slow
+some
+small
+somebody
+smell
+smart
+somehow
+someone
+smile
+something
+-something
+smog
+sometimes
+smoke
+somewhat
+smooth
+somewhere
+snack
+son
+snake
+song
+sneeze
+soon
+snow
+sorrow
+snowy
+sorry
+sort
+soccer
+social
+soul
+sound
+socialist
+soup
+society
+sock
+sour
+source
+sofa
+south
+southern
+stair
+sow
+space
+stamp
+spare
+stand
+standard
+speak
+-speak
+speaker
+star
+-star
+special
+stare
+start
+specialist
+species
+starve
+specific
+state
+station
+statistic
+speech
+statue
+speed
+stay
+spell
+steak
+spend
+steal
+spirit
+steam
+splendid
+steel
+sponsor
+spoon
+step
+step-
+sport
+stick
+spot
+still
+spread
+stimulate
+spring
+stomach
+spy
+stone
+square
+stop
+stability
+stadium
+store
+staff
+storm
+-storm
+stage
+story
+straight
+subscribe
+straightforward
+subsequent
+substance
+strait
+strange
+substantial
+stranger
+suburb
+strategy
+subway
+strawberry
+succeed
+stream
+success
+street
+successful
+strength
+such
+strengthen
+sudden
+stretch
+suffer
+sufficient
+stress
+strict
+sugar
+strike
+suggest
+string
+suggestion
+strong
+structure
+suit
+suitable
+struggle
+student
+sum
+summary
+studio
+summer
+study
+stuff
+sun
+sun.
+sunday
+stupid
+sunny
+style
+-style
+subject
+super
+super-
+superb
+subjective
+superior
+submit
+supermarket
+supply
+suppose
+table
+sure
+surf
+tablet
+tackle
+surface
+surgeon
+tail
+tailor
+surgery
+take
+surprise
+tale
+surround
+talent
+talk
+survey
+tall
+tank
+survive
+suspect
+tape
+target
+suspend
+sustain
+task
+sweat
+taste
+tax
+sweater
+sweep
+taxi
+sweet
+tea
+swim
+teach
+teacher
+swing
+teapot
+switch
+symbol
+tear
+sympathy
+technique
+symphony
+technology
+system
+teenager
+then
+telephone
+theory
+television
+tv
+there
+tell
+therefore
+temperature
+these
+temple
+they
+temporary
+thick
+ten
+thin
+tend
+thing
+tendency
+think
+tennis
+thinking
+tension
+third
+tenth
+thirsty
+term
+-term
+thirteen
+terrible
+thirty
+territory
+this
+test
+thorough
+text
+those
+than
+though
+thank
+thought
+that
+thousand
+the
+threat
+theft
+theatre
+threaten
+their
+three
+through
+them
+throughout
+theme
+throw
+themselves
+thunder
+thus
+thursday
+toothache
+top
+top-
+ticket
+topic
+tidy
+total
+tie
+touch
+tiger
+tough
+tight
+tour
+time
+-time
+tourist
+tiny
+tournament
+tip
+towards
+tired
+towel
+tissue
+tower
+title
+town
+toy
+track
+toast
+tobacco
+trade
+today
+tradition
+together
+traditional
+toilet
+traffic
+tolerate
+train
+training
+tomato
+tomorrow
+transform
+translate
+ton
+tone
+transport
+trap
+tonight
+travel
+too
+tool
+treasure
+tooth
+teeth
+treat
+wallet
+weekend
+wander
+weekly
+want
+weep
+war
+weigh
+weight
+ward
+-ward
+warm
+welcome
+warn
+welfare
+well
+we'll
+wash
+west
+washroom
+western
+waste
+wet
+watch
+whale
+water
+-water
+what
+watermelon
+whatever
+wave
+wheat
+way
+wheel
+we
+when
+weak
+whenever
+wealth
+where
+weapon
+whether
+wear
+which
+weather
+while
+website
+whisper
+wedding
+white
+weed
+wednesday
+who
+the who
+whole
+week
+whom
+weekday
+whose
+wool
+why
+wide
+word
+widespread
+work
+-work
+wife
+worker
+the wi
+wi
+hi-fi
+world
+wild
+worry
+worse
+will
+win
+worst
+wind
+worth
+window
+worthwhile
+windy
+worthy
+-worthy
+wine
+would
+wing
+wound
+wrap
+winner
+wrestle
+winter
+wire
+wrinkle
+wisdom
+wrist
+wise
+-wise
+write
+wish
+writer
+with
+wrong
+withdraw
+within
+without
+x
+witness
+woman
+-woman
+women
+wonder
+yard
+wonderful
+year
+-year
+wood
+yellow
+yourself
+yes
+yesterday
+youth
+yet
+yogurt
+z, z
+you
+zero
+zone
+young
+your
+yours
+up
+up-
+era
+energy
+household
+housework
+laugh
+slim
+altogether
+ankle
+apart
+atlantic
+cartoon
+cattle
+chest
+chairman
+children
+choose
+clay
+clock
+conflict
+consequence
+cruel
+enable
+journey
+republic
+telescope
+warning
+blog
+count
+fifteen
+hers
+mean
+partner
+pretend
+skirt
+support
+team
+plot
+refer to sb/sth
+consist in sth
+devote sth to sth/sb
+rely on/upon sb/sth
+a
+above
+abroad
+absence
+absent
+absolutely
+absorb
+abstract
+abuse
+academic
+aboard
+able
+-able
+ability
+-ability
+abandon
+about

+ 121 - 0
tktool.py

@@ -0,0 +1,121 @@
+import abc
+import traceback
+import threading
+from tkinter.font import Font
+from typing import Optional, List
+
+
+def make_font(**kwargs):
+    return Font(family=r"./noto/NotoSansSC-Thin.otf", **kwargs)
+
+
+class TkEventMain(metaclass=abc.ABCMeta):
+    """
+    Tkinter 处理子线程基类
+    """
+    tk_refresh_delay = 50
+
+    def __init__(self):
+        self._event_list: List[TkEventBase] = []
+        self.set_after_run(self.tk_refresh_delay, lambda: self.run_event())
+
+    def push_event(self, event: "TkEventBase"):  # 添加子线程
+        self._event_list.append(event)
+        self.show_loading(event.get_title())
+        self.run_event()
+
+    def run_event(self):  # 定时任务, 检测子线程是否结束, 并运行 done_after_event
+        if len(self._event_list) == 0:
+            return
+
+        new_event: List[TkEventBase] = []
+        done_event: List[TkEventBase] = []
+        for event in self._event_list:
+            if event.is_end():
+                done_event.append(event)
+            else:
+                new_event.append(event)
+        self._event_list = new_event
+        if len(self._event_list) == 0:
+            self.stop_loading()
+
+        for event in done_event:  # 隐藏进度条后执行Event-GUI任务
+            try:
+                event.done_after_event()
+            except:
+                traceback.print_exc()
+        self.set_after_run_now(self.tk_refresh_delay, self.run_event)
+
+    @abc.abstractmethod
+    def show_loading(self, title: str):  # 有子线程时显示加载
+        ...
+
+    @abc.abstractmethod
+    def stop_loading(self):  # 子线程运行完成后关闭加载
+        ...
+
+    @abc.abstractmethod
+    def set_after_run(self, ms, func, *args):
+        ...
+
+    @abc.abstractmethod
+    def set_after_run_now(self, ms, func, *args):
+        ...
+
+
+class TkEventBase(metaclass=abc.ABCMeta):
+    """
+    Tkinter 子线程任务
+    """
+
+    def __init__(self):
+        self.thread: Optional[TkThreading] = None  # 子线程
+
+    def is_end(self) -> bool:  # 判断子线程是否结束
+        if self.thread is not None and not self.thread.is_alive():
+            return True
+        return False
+
+    @abc.abstractmethod
+    def get_title(self) -> str:  # 获取任务名字
+        ...
+
+    def done_after_event(self):  # 子线程结束后, 在GUI线程执行的代码
+        if self.thread is not None:
+            self.thread.wait_event()
+
+
+class TkThreading(threading.Thread):
+    """
+    tkinter 子线程
+    """
+
+    def __init__(self, func, *args, start_now: bool = True):
+        """
+        :param func: 子线程函数
+        :param args: 子线程参数
+        :param start_now: 是否马上运行 (否则要回调.start函数)
+        """
+        threading.Thread.__init__(self)
+        self.func = func
+        self.args = args
+        self.result = None
+
+        if start_now:
+            self.start()
+
+    def run(self):
+        try:
+            self.result = self.func(*self.args)
+        except:
+            traceback.print_exc()
+        finally:
+            del self.func, self.args
+
+    def wait_event(self) -> any:
+        """
+        等待线程结束
+        :return: 线程函数的返回值
+        """
+        self.join()
+        return self.result

+ 208 - 0
ui.py

@@ -0,0 +1,208 @@
+import tktool
+import tkinter
+from typing import List, Tuple, Callable, Optional
+import abc
+
+
+class HEnglishTkinter(tktool.TkEventMain, metaclass=abc.ABCMeta):
+    tk_zoom = 1
+
+    def set_after_run(self, ms, func, *args):  # 正常运行前设置定时任务 super.__init__可能会调用
+        self.init_after_run_list.append((ms, func, args))
+
+    def __conf_set_after_run(self):  # 配合 set_after_run 使用
+        for ms, func, args in self.init_after_run_list:
+            self.set_after_run_now(ms, func, *args)
+
+    def set_after_run_now(self, ms, func, *args):  # 正常运行时设置定时任务
+        self._window.after(ms, func, *args)
+
+    def __init__(self, title: str,
+                 top: Optional["HEnglishTkinter"] = None,
+                 size: Tuple[float, float] = ((1 / 3), (2 / 3))):
+        self.init_after_run_list: List[Tuple[int, Callable, Tuple]] = []
+        super(HEnglishTkinter, self).__init__()
+
+        if top:
+            self._window = tkinter.Toplevel(top._window)
+        else:
+            self._window = tkinter.Tk()
+
+        self._sys_height = self._window.winfo_screenheight()
+        self._sys_width = self._window.winfo_screenwidth()
+
+        self._win_height = int(self._sys_height * size[1] * self.tk_zoom)  # 窗口高度
+        self._win_width = int(self._sys_width * size[0] * self.tk_zoom)  # 窗口宽度
+
+        self.__conf_windows(title)
+        self.__conf_set_after_run()
+
+    def __conf_windows(self, title: str):
+        self._window.title(title)
+        self._window.geometry(f'{self._win_width}x{self._win_height}')
+        self._window['bg'] = '#F0FFFF'
+        self._window.resizable(True, True)  # 禁止缩放
+        self._window.overrideredirect(False)  # 显示标题栏
+        self._window.bind('<Configure>', self.__window_resize)  # 调整界面大小
+        self._window.minsize(int(self._sys_width * (1 / 3) * self.tk_zoom),
+                             int(self._sys_height * (1 / 3) * self.tk_zoom))
+
+        self._create_windows()
+        self._set_windows()
+
+    def __window_resize(self, event=None):
+        if self._win_width != self._window.winfo_width() or self._win_height != self._window.winfo_height():
+            self._win_height = self._window.winfo_height()
+            self._win_width = self._window.winfo_width()
+            self._set_windows()
+
+    @abc.abstractmethod
+    def _create_windows(self):
+        pass
+
+    @abc.abstractmethod
+    def _set_windows(self):
+        pass
+
+    def mainloop(self):
+        self._window.mainloop()
+
+
+class HEnglish(HEnglishTkinter):
+    def __init__(self):
+        super(HEnglish, self).__init__("H-English")
+
+    def _create_windows(self):
+        self._title_label = tkinter.Label(self._window)
+        self._control_frame = tkinter.Frame(self._window)
+        self._control_btn = [tkinter.Button(self._control_frame) for _ in range(6)]
+
+    def _set_windows(self):
+        self.__conf_title()
+        self.__conf_control_btn()
+
+    def __conf_title(self):
+        if self._win_width >= self._win_height:
+            font = tktool.make_font(size=int(self._win_height * 0.06), weight="bold")
+        else:
+            font = tktool.make_font(size=int(self._win_width * 0.05), weight="bold")
+        self._title_label['font'] = font
+        self._title_label['bg'] = '#F0FFFF'
+        self._title_label['text'] = "Huan-English-Dictionary"  # 使用英语标题在GUI更美观
+        self._title_label['anchor'] = 'c'
+        self._title_label.place(relx=0.0, rely=0.03, relwidth=1.0, relheight=0.13)
+        self._title = tkinter.Label()
+
+    def __conf_control_btn(self):
+        if self._win_width >= self._win_height:
+            font = tktool.make_font(size=int(self._win_height * 0.03))
+            self._control_btn[0].place(relx=0.07, rely=0.10, relwidth=0.4, relheight=0.2)
+            self._control_btn[1].place(relx=0.53, rely=0.10, relwidth=0.4, relheight=0.2)
+            self._control_btn[2].place(relx=0.07, rely=0.40, relwidth=0.4, relheight=0.2)
+            self._control_btn[3].place(relx=0.53, rely=0.40, relwidth=0.4, relheight=0.2)
+            self._control_btn[4].place(relx=0.07, rely=0.70, relwidth=0.4, relheight=0.2)
+            self._control_btn[5].place(relx=0.53, rely=0.70, relwidth=0.4, relheight=0.2)
+        else:
+            font = tktool.make_font(size=int(self._win_width * 0.03))
+            self._control_btn[0].place(relx=0.1, rely=0.08, relwidth=0.8, relheight=0.1)
+            self._control_btn[1].place(relx=0.1, rely=0.23, relwidth=0.8, relheight=0.1)
+            self._control_btn[2].place(relx=0.1, rely=0.38, relwidth=0.8, relheight=0.1)
+            self._control_btn[3].place(relx=0.1, rely=0.53, relwidth=0.8, relheight=0.1)
+            self._control_btn[4].place(relx=0.1, rely=0.68, relwidth=0.8, relheight=0.1)
+            self._control_btn[5].place(relx=0.1, rely=0.83, relwidth=0.8, relheight=0.1)
+
+        self._control_frame['bg'] = "#FFFFFF"
+        self._control_frame['relief'] = "ridge"
+        self._control_frame['bd'] = 5
+        self._control_frame.place(relx=0.05, rely=0.20, relwidth=0.90, relheight=0.75)
+
+        for i in zip(self._control_btn,
+                     ["Word Test", "Dictionary", "Export", "Import", "Delete", "About"],
+                     ["#1E90FF", "#FF69B4", "#FF4500", "#4169E1", "#00FF7F", "#C71585"],
+                     [None, None, None, self.import_word, None, None]):
+            i[0]['font'] = font
+            i[0]['fg'] = "#000000"
+            i[0]['bg'] = i[2]
+            i[0]['activeforeground'] = "#FFFFFF"
+            i[0]['activebackground'] = i[2]
+            i[0]['anchor'] = 'c'
+            i[0]['relief'] = "ridge"
+            i[0]['bd'] = 5
+            i[0]['text'] = i[1]
+            i[0]['command'] = i[3]
+
+    def import_word(self):
+        Import(self, self._window)
+
+    def show_loading(self, title: str):  # 有子线程时显示加载
+        ...
+
+    def stop_loading(self):  # 子线程运行完成后关闭加载
+        ...
+
+
+class Import(HEnglishTkinter):
+    def __init__(self, father: HEnglish, father_windows: tkinter.Tk):
+        super(Import, self).__init__("Import", father, size=(1 / 3, 1 / 3))
+        self._father = father
+        self._father_windows = father_windows
+
+    def _create_windows(self):
+        self._title_label = tkinter.Label(self._window)
+        self._control_btn = [tkinter.Button(self._window) for _ in range(6)]
+
+    def _set_windows(self):
+        self.__conf_title()
+        self.__conf_control_btn()
+
+    def __conf_title(self):
+        if self._win_width >= self._win_height:
+            font = tktool.make_font(size=int(self._win_height * 0.06), weight="bold")
+        else:
+            font = tktool.make_font(size=int(self._win_width * 0.05), weight="bold")
+        self._title_label['font'] = font
+        self._title_label['bg'] = '#F0FFFF'
+        self._title_label['text'] = "Import Word"  # 使用英语标题在GUI更美观
+        self._title_label['anchor'] = 'c'
+        self._title_label.place(relx=0.0, rely=0.03, relwidth=1.0, relheight=0.13)
+        self._title = tkinter.Label()
+
+    def __conf_control_btn(self):
+        if self._win_width >= self._win_height:
+            font = tktool.make_font(size=int(self._win_height * 0.04))
+            self._control_btn[0].place(relx=0.07, rely=0.28, relwidth=0.4, relheight=0.2)
+            self._control_btn[1].place(relx=0.53, rely=0.28, relwidth=0.4, relheight=0.2)
+            self._control_btn[2].place(relx=0.07, rely=0.66, relwidth=0.4, relheight=0.2)
+            self._control_btn[3].place(relx=0.53, rely=0.66, relwidth=0.4, relheight=0.2)
+        else:
+            font = tktool.make_font(size=int(self._win_width * 0.04))
+            self._control_btn[0].place(relx=0.1, rely=0.20, relwidth=0.8, relheight=0.1)
+            self._control_btn[1].place(relx=0.1, rely=0.33, relwidth=0.8, relheight=0.1)
+            self._control_btn[2].place(relx=0.1, rely=0.46, relwidth=0.8, relheight=0.1)
+            self._control_btn[3].place(relx=0.1, rely=0.59, relwidth=0.8, relheight=0.1)
+
+        for i in zip(self._control_btn,
+                     ["From Text", "From CSV", "From Excel", "From Json"],
+                     ["#1E90FF", "#FF69B4", "#C71585", "#00FF7F"],
+                     [None, None, None, None]):
+            i[0]['font'] = font
+            i[0]['fg'] = "#000000"
+            i[0]['bg'] = i[2]
+            i[0]['activeforeground'] = "#FFFFFF"
+            i[0]['activebackground'] = i[2]
+            i[0]['anchor'] = 'c'
+            i[0]['relief'] = "ridge"
+            i[0]['bd'] = 5
+            i[0]['text'] = i[1]
+            i[0]['command'] = i[3]
+
+    def show_loading(self, title: str):  # 有子线程时显示加载
+        ...
+
+    def stop_loading(self):  # 子线程运行完成后关闭加载
+        ...
+
+
+if __name__ == '__main__':
+    hgui = HEnglish()
+    hgui.mainloop()

+ 147 - 0
word.py

@@ -0,0 +1,147 @@
+"""
+文件名: word.py
+通过检索网络词典获得一个词语的中文翻译
+使用requests生成一个网络请求
+使用bs4解析网页
+"""
+
+import requests
+from bs4 import BeautifulSoup
+from typing import Optional, Dict
+
+
+class WordDict:
+    __data_set_search = "english-chinese-simplified"
+    __url = f"https://dictionary.cambridge.org/zhs/%E6%90%9C%E7%B4%A2/direct/?datasetsearch={__data_set_search}"
+
+    def __init__(self, user_agent: Optional[str] = None, proxies: Optional[dict] = None):
+        if user_agent is None:
+            user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) "
+                          "Chrome/17.0.963.56 Safari/535.11 ")
+
+        if proxies is None:
+            proxies = {'http': "http://localhost:8889", 'https': "http://localhost:8889"}  # 不走系统代理
+
+        self.headers = {"User-Agent": user_agent}  # 配置请求头
+        self.proxies = proxies
+
+    def set_headers(self, headers: dict):
+        self.headers.update(headers)
+
+    def set_proxies(self, proxies: dict):
+        self.proxies.update(proxies)
+
+    def get_requests(self, q: str) -> "Response":
+        response = requests.get(self.__url,
+                                params={"q": q},
+                                headers=self.headers,
+                                proxies=self.proxies)
+        return Response(response)
+
+
+class Response:
+    def __init__(self, response: requests.Response):
+        self._res = response
+        self._soup = None
+        if self._res.status_code != 200:
+            return
+
+        self._soup = BeautifulSoup(self._res.text, "html.parser")
+        self.di_body = self._soup.find(name="div", attrs={"class": "di-body"})
+        if self.di_body is None:
+            self._soup = None
+            return
+
+        self.entry = [(i, 1) for i in self.di_body.findAll(name="div", attrs={"class": "pr entry-body__el"})]
+        self.entry += [(i, 2) for i in self.di_body.findAll(name="div", attrs={"class": "pv-block"})]
+        if len(self.entry) == 0:
+            self._soup = None
+            return
+
+        self.res: Dict[str: Word] = {}
+        for i, f in self.entry:
+            name = i.find(name="div", attrs={"class": "di-title"})
+            if name is None:
+                continue
+            if f == 1:
+                name_string = str(name.span.span.text)
+                part = i.find(name="div", attrs={"class": "posgram dpos-g hdib lmr-5"})
+                if part is None:
+                    part_string = "unknown"
+                else:
+                    part_string = str(part.span.text)
+            else:
+                name_string = str(name.h2.b.text)
+                part = i.find(name="div", attrs={"class": "pos dpos"})
+                if part is None:
+                    part_string = "unknown"
+                else:
+                    part_string = str(part.span.text)
+
+            word = self.res.get(name_string)
+            if word is None:
+                word = Word(name_string)
+                self.res[name_string] = word
+
+            h = i.find(name="div", attrs={"class": "ddef_h"})
+            if h is None:
+                continue
+            english = str(h.div.text)
+
+            b = i.find(name="div", attrs={"class": "def-body ddef_b"})
+            if b is None:
+                continue
+            chinese = str(b.span.text)
+
+            comment = Word.Comment(part_string, english, chinese)
+            eg = b.findAll(name="div", attrs={"class": "examp dexamp"})
+            for e in eg:
+                es = e.find(name="span", attrs={"class": "eg deg"})
+                cs = e.find(name="span", attrs={"class": "trans dtrans dtrans-se hdb break-cj"})
+                if es is None:
+                    continue
+                es = str(es.text).replace("##", " ").replace("@@", " ")
+                if cs is not None:
+                    cs = str(cs.text).replace("##", " ").replace("@@", " ")
+                else:
+                    cs = ""
+                comment.add_eg(f"{es}##{cs}")
+            word.add_comment(comment)
+        if len(self.res) == 0:
+            self._soup = None
+
+    @property
+    def is_find(self):
+        return self._soup is not None
+
+
+class Word:
+    class Comment:
+        def __init__(self, part: str, english: str, chinese: str):
+            self.part = part   # 词性
+            self.english = english
+            self.chinese = chinese
+            self.eg = []
+
+        def add_eg(self, eg: str):
+            self.eg.append(eg)
+
+        def __str__(self):
+            return f"{self.part} {self.english} {self.chinese} \neg: {self.eg}"
+
+    def __init__(self, name: str):
+        self.name = name
+        self.comment: Dict[str: "Word.Comment"] = {}  # 注释
+
+    def add_comment(self, c: Comment):
+        if self.comment.get(c.english) is None:
+            self.comment[c.english] = c
+
+    def __str__(self):
+        ret = f"{self.name}:\n"
+        for i in self.comment:
+            ret += f'note: {self.comment[i]};\n'
+        return ret
+
+
+word_dict = WordDict()