Compare commits
	
		
			1 Commits 
		
	
	
		
			master
			...
			Refactor_q
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | ea16ea6673 | 
|  | @ -1,3 +1,6 @@ | ||||||
|  | """ | ||||||
|  | This module provides functions about article | ||||||
|  | """ | ||||||
| from WordFreq import WordFreq | from WordFreq import WordFreq | ||||||
| from wordfreqCMD import youdao_link, sort_in_descending_order | from wordfreqCMD import youdao_link, sort_in_descending_order | ||||||
| from UseSqlite import InsertQuery, RecordQuery | from UseSqlite import InsertQuery, RecordQuery | ||||||
|  | @ -46,7 +49,6 @@ def get_today_article(user_word_list, articleID): | ||||||
|     d1 = load_freq_history(path_prefix + 'static/frequency/frequency.p') |     d1 = load_freq_history(path_prefix + 'static/frequency/frequency.p') | ||||||
|     d2 = load_freq_history(path_prefix + 'static/words_and_tests.p') |     d2 = load_freq_history(path_prefix + 'static/words_and_tests.p') | ||||||
|     d3 = get_difficulty_level(d1, d2) |     d3 = get_difficulty_level(d1, d2) | ||||||
| 
 |  | ||||||
|     d = {} |     d = {} | ||||||
|     d_user = load_freq_history(user_word_list) |     d_user = load_freq_history(user_word_list) | ||||||
|     user_level = user_difficulty_level(d_user, d3)  # more consideration as user's behaviour is dynamic. Time factor should be considered. |     user_level = user_difficulty_level(d_user, d3)  # more consideration as user's behaviour is dynamic. Time factor should be considered. | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								app/Login.py
								
								
								
								
							
							
						
						
									
										29
									
								
								app/Login.py
								
								
								
								
							|  | @ -1,3 +1,6 @@ | ||||||
|  | """ | ||||||
|  | This module provides methods for Login | ||||||
|  | """ | ||||||
| import hashlib | import hashlib | ||||||
| import string | import string | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
|  | @ -7,15 +10,17 @@ path_prefix = '/var/www/wordfreq/wordfreq/' | ||||||
| path_prefix = './'  # comment this line in deployment | path_prefix = './'  # comment this line in deployment | ||||||
| 
 | 
 | ||||||
| def verify_pass(newpass,oldpass): | def verify_pass(newpass,oldpass): | ||||||
|     if(newpass==oldpass): |     if newpass==oldpass: | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| def verify_user(username, password): | def verify_user(username, password): | ||||||
|     rq = RecordQuery(path_prefix + 'static/wordfreqapp.db') |     rq = RecordQuery(path_prefix + 'static/wordfreqapp.db') | ||||||
|     password = md5(username + password) |     password = md5(username + password) | ||||||
|     rq.instructions_with_parameters("SELECT * FROM user WHERE name=:username AND password=:password", dict( |     rq.instructions_with_parameters( | ||||||
|         username=username, password=password))  # the named style https://docs.python.org/3/library/sqlite3.html |         "SELECT * FROM user WHERE name=:username AND password=:password", | ||||||
|  |         dict(   # the named style https://docs.python.org/3/library/sqlite3.html | ||||||
|  |             username=username, | ||||||
|  |             password=password)) | ||||||
|     rq.do_with_parameters() |     rq.do_with_parameters() | ||||||
|     result = rq.get_results() |     result = rq.get_results() | ||||||
|     return result != [] |     return result != [] | ||||||
|  | @ -23,12 +28,19 @@ def verify_user(username, password): | ||||||
| 
 | 
 | ||||||
| def add_user(username, password): | def add_user(username, password): | ||||||
|     start_date = datetime.now().strftime('%Y%m%d') |     start_date = datetime.now().strftime('%Y%m%d') | ||||||
|     expiry_date = (datetime.now() + timedelta(days=30)).strftime('%Y%m%d') # will expire after 30 days |     # will expire after 30 days | ||||||
|  |     expiry_date = (datetime.now() + timedelta(days=30)).strftime('%Y%m%d') | ||||||
|     # 将用户名和密码一起加密,以免暴露不同用户的相同密码 |     # 将用户名和密码一起加密,以免暴露不同用户的相同密码 | ||||||
|     password = md5(username + password) |     password = md5(username + password) | ||||||
|     rq = InsertQuery(path_prefix + 'static/wordfreqapp.db') |     rq = InsertQuery(path_prefix + 'static/wordfreqapp.db') | ||||||
|     rq.instructions_with_parameters("INSERT INTO user VALUES (:username, :password, :start_date, :expiry_date)", dict( |     rq.instructions_with_parameters( | ||||||
|         username=username, password=password, start_date=start_date, expiry_date=expiry_date)) |         "INSERT INTO user VALUES (:username, :password, :start_date, :expiry_date)", | ||||||
|  |         dict( | ||||||
|  |             username=username, | ||||||
|  |             password=password, | ||||||
|  |             start_date=start_date, | ||||||
|  |             expiry_date=expiry_date | ||||||
|  |         )) | ||||||
|     rq.do_with_parameters() |     rq.do_with_parameters() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -96,7 +108,7 @@ class UserName: | ||||||
|         if ' ' in self.username: # a user name must not include a whitespace |         if ' ' in self.username: # a user name must not include a whitespace | ||||||
|             return 'Whitespace is not allowed in the user name.' |             return 'Whitespace is not allowed in the user name.' | ||||||
|         for c in self.username: # a user name must not include special characters, except non-leading periods or underscores |         for c in self.username: # a user name must not include special characters, except non-leading periods or underscores | ||||||
|             if c in string.punctuation and c is not '.' and c is not '_': |             if c in string.punctuation and c != '.' and c != '_': | ||||||
|                 return f'{c} is not allowed in the user name.' |                 return f'{c} is not allowed in the user name.' | ||||||
|         if self.username in ['signup', 'login', 'logout', 'reset', 'mark', 'back', 'unfamiliar', 'familiar', 'del']: |         if self.username in ['signup', 'login', 'logout', 'reset', 'mark', 'back', 'unfamiliar', 'familiar', 'del']: | ||||||
|             return 'You used a restricted word as your user name.  Please come up with a better one.' |             return 'You used a restricted word as your user name.  Please come up with a better one.' | ||||||
|  | @ -110,4 +122,3 @@ class WarningMessage: | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return UserName(self.s).validate() |         return UserName(self.s).validate() | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -2,9 +2,12 @@ | ||||||
| # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | ||||||
| # Written permission must be obtained from the author for commercial uses. | # Written permission must be obtained from the author for commercial uses. | ||||||
| ########################################################################### | ########################################################################### | ||||||
| 
 | """ | ||||||
| from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order | This module produces word frequency | ||||||
|  | """ | ||||||
| import string | import string | ||||||
|  | from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class WordFreq: | class WordFreq: | ||||||
|     def __init__(self, s): |     def __init__(self, s): | ||||||
|  | @ -22,4 +25,3 @@ class WordFreq: | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     f = WordFreq('BANANA; Banana, apple ORANGE Banana banana.') |     f = WordFreq('BANANA; Banana, apple ORANGE Banana banana.') | ||||||
|     print(f.get_freq()) |     print(f.get_freq()) | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,54 +1,54 @@ | ||||||
|  | """ | ||||||
|  | This module provides services about account. | ||||||
|  | """ | ||||||
| from flask import * | from flask import * | ||||||
| from Login import check_username_availability, verify_user, add_user, get_expiry_date, change_password, WarningMessage | from Login import check_username_availability, \ | ||||||
|  |     verify_user, add_user, get_expiry_date, change_password, WarningMessage | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # 初始化蓝图 | # 初始化蓝图 | ||||||
| accountService = Blueprint("accountService", __name__) | accountService = Blueprint("accountService", __name__) | ||||||
| 
 | 
 | ||||||
| ### Sign-up, login, logout ### | 
 | ||||||
|  | # Sign-up, login, logout | ||||||
| @accountService.route("/signup", methods=['GET', 'POST']) | @accountService.route("/signup", methods=['GET', 'POST']) | ||||||
| def signup(): | def signup(): | ||||||
|     ''' |     ''' | ||||||
|     注册 |     注册 | ||||||
|     :return: 根据注册是否成功返回不同界面 |     :return: 根据注册是否成功返回不同界面 | ||||||
|     ''' |     ''' | ||||||
|  |     # GET方法直接返回注册页面 | ||||||
|     if request.method == 'GET': |     if request.method == 'GET': | ||||||
|         # GET方法直接返回注册页面 |  | ||||||
|         return render_template('signup.html') |         return render_template('signup.html') | ||||||
|     elif request.method == 'POST': |     if request.method == 'POST': | ||||||
|         # POST方法需判断是否注册成功,再根据结果返回不同的内容 |         # POST方法需判断是否注册成功,再根据结果返回不同的内容 | ||||||
|         username = escape(request.form['username']) |         username = escape(request.form['username']) | ||||||
|         password = escape(request.form['password']) |         password = escape(request.form['password']) | ||||||
|         password2 = escape(request.form['password2']) |         password2 = escape(request.form['password2']) | ||||||
|          |  | ||||||
|         #! 添加如下代码为了过滤注册时的非法字符 |         #! 添加如下代码为了过滤注册时的非法字符 | ||||||
|         warn = WarningMessage(username) |         warn = WarningMessage(username) | ||||||
|         if str(warn) != 'OK': |         if str(warn) != 'OK': | ||||||
|             return str(warn) |             return str(warn) | ||||||
|          |  | ||||||
|         available = check_username_availability(username) |         available = check_username_availability(username) | ||||||
|         if not available: # 用户名不可用 |         if not available: # 用户名不可用 | ||||||
|             flash('用户名 %s 已经被注册。' % (username)) |             flash('用户名 %s 已经被注册。' % (username)) | ||||||
|             return render_template('signup.html') |             return render_template('signup.html') | ||||||
|         elif len(password.strip()) < 4: # 密码过短 |         if len(password.strip()) < 4: # 密码过短 | ||||||
|             return '密码过于简单。' |             return '密码过于简单。' | ||||||
|         elif password != password2: |         if password != password2: | ||||||
|             return '确认密码与输入密码不一致!' |             return '确认密码与输入密码不一致!' | ||||||
|         else: # 添加账户信息 |         add_user(username, password)# 添加账户信息 | ||||||
|             add_user(username, password) |         verified = verify_user(username, password) | ||||||
|             verified = verify_user(username, password) |         if verified: | ||||||
|             if verified: |             # 写入session | ||||||
|                 # 写入session |             session['logged_in'] = True | ||||||
|                 session['logged_in'] = True |             session[username] = username | ||||||
|                 session[username] = username |             session['username'] = username | ||||||
|                 session['username'] = username |             session['expiry_date'] = get_expiry_date(username) | ||||||
|                 session['expiry_date'] = get_expiry_date(username) |             session['articleID'] = None | ||||||
|                 session['articleID'] = None |             return '<p>恭喜,你已成功注册, 你的用户名是 <a href="%s">%s</a>。</p>\ | ||||||
|                 return '<p>恭喜,你已成功注册, 你的用户名是 <a href="%s">%s</a>。</p>\ |             <p><a href="/%s">开始使用</a> <a href="/">返回首页</a><p/>' % (username, username, username) | ||||||
|                 <p><a href="/%s">开始使用</a> <a href="/">返回首页</a><p/>' % (username, username, username) |         return '用户名密码验证失败。' | ||||||
|             else: |  | ||||||
|                 return '用户名密码验证失败。' |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @accountService.route("/login", methods=['GET', 'POST']) | @accountService.route("/login", methods=['GET', 'POST']) | ||||||
|  | @ -62,11 +62,10 @@ def login(): | ||||||
|         if not session.get('logged_in'): |         if not session.get('logged_in'): | ||||||
|             # 未登录,返回登录页面 |             # 未登录,返回登录页面 | ||||||
|             return render_template('login.html') |             return render_template('login.html') | ||||||
|         else: |         # 已登录,提示信息并显示登出按钮 | ||||||
|             # 已登录,提示信息并显示登出按钮 |         return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % ( | ||||||
|             return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % ( |  | ||||||
|                 session['username'], session['username']) |                 session['username'], session['username']) | ||||||
|     elif request.method == 'POST': |     if request.method == 'POST': | ||||||
|         # POST方法用于判断登录是否成功 |         # POST方法用于判断登录是否成功 | ||||||
|         # check database and verify user |         # check database and verify user | ||||||
|         username = escape(request.form['username']) |         username = escape(request.form['username']) | ||||||
|  | @ -81,8 +80,7 @@ def login(): | ||||||
|             session['expiry_date'] = user_expiry_date |             session['expiry_date'] = user_expiry_date | ||||||
|             session['articleID'] = None |             session['articleID'] = None | ||||||
|             return redirect(url_for('user_bp.userpage', username=username)) |             return redirect(url_for('user_bp.userpage', username=username)) | ||||||
|         else: |         return '无法通过验证。' | ||||||
|             return '无法通过验证。' |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @accountService.route("/logout", methods=['GET', 'POST']) | @accountService.route("/logout", methods=['GET', 'POST']) | ||||||
|  | @ -111,21 +109,18 @@ def reset(): | ||||||
|     if request.method == 'GET': |     if request.method == 'GET': | ||||||
|         # GET请求返回修改密码页面 |         # GET请求返回修改密码页面 | ||||||
|         return render_template('reset.html', username=session['username'], state='wait') |         return render_template('reset.html', username=session['username'], state='wait') | ||||||
|     else: |     # POST请求用于提交修改后信息 | ||||||
|         # POST请求用于提交修改后信息 |     old_password = escape(request.form['old-password']) | ||||||
|         old_password = escape(request.form['old-password']) |     new_password = escape(request.form['new-password']) | ||||||
|         new_password = escape(request.form['new-password']) |     re_new_password = escape(request.form['re-new-password'])  # 确认新密码 | ||||||
| 
 |     if re_new_password != new_password: #验证新密码两次输入是否相同 | ||||||
|         re_new_password = escape(request.form['re-new-password'])  # 确认新密码 |         return '新密码不匹配,请重新输入' | ||||||
|         if re_new_password != new_password: #验证新密码两次输入是否相同 |     if len(new_password) < 4: #验证新密码长度,原则参照注册模块 | ||||||
|             return '新密码不匹配,请重新输入' |         return '密码过于简单。(密码长度至少4位)' | ||||||
|         if len(new_password) < 4: #验证新密码长度,原则参照注册模块 |     flag = change_password(username, old_password, new_password) # flag表示是否修改成功 | ||||||
|             return '密码过于简单。(密码长度至少4位)' |     if flag: | ||||||
| 
 |         session['logged_in'] = False | ||||||
|         flag = change_password(username, old_password, new_password) # flag表示是否修改成功 |         return \ | ||||||
|         if flag: |  | ||||||
|             session['logged_in'] = False |  | ||||||
|             return \ |  | ||||||
| ''' | ''' | ||||||
| <script> | <script> | ||||||
| alert('密码修改成功,请重新登录。'); | alert('密码修改成功,请重新登录。'); | ||||||
|  | @ -134,8 +129,7 @@ window.location.href="/login"; | ||||||
| 
 | 
 | ||||||
| ''' | ''' | ||||||
| 
 | 
 | ||||||
|         else: | 
 | ||||||
|             return \ |  | ||||||
| ''' | ''' | ||||||
| <script> | <script> | ||||||
| alert('密码修改失败'); | alert('密码修改失败'); | ||||||
|  |  | ||||||
|  | @ -3,8 +3,10 @@ | ||||||
| # Written permission must be obtained from the author for commercial uses. | # Written permission must be obtained from the author for commercial uses. | ||||||
| ########################################################################### | ########################################################################### | ||||||
| 
 | 
 | ||||||
| # Purpose: compute difficulty level of a English text | """ | ||||||
| 
 | This module provides functions for calculating user words difficulty | ||||||
|  | Purpose: compute difficulty level of a English text | ||||||
|  | """ | ||||||
| import pickle | import pickle | ||||||
| import math | import math | ||||||
| from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order, sort_in_ascending_order | from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order, sort_in_ascending_order | ||||||
|  | @ -23,8 +25,8 @@ def difficulty_level_from_frequency(word, d): | ||||||
|         return level |         return level | ||||||
| 
 | 
 | ||||||
|     if 'what' in d: |     if 'what' in d: | ||||||
|         ratio = (d['what']+1)/(d[word]+1) # what is a frequent word |         ratio = (d['what'] + 1) / (d[word] + 1)  # what is a frequent word | ||||||
|         level = math.log( max(ratio, 1), 2) |         level = math.log(max(ratio, 1), 2) | ||||||
| 
 | 
 | ||||||
|     level = min(level, 8) |     level = min(level, 8) | ||||||
|     return level |     return level | ||||||
|  | @ -33,18 +35,18 @@ def difficulty_level_from_frequency(word, d): | ||||||
| def get_difficulty_level(d1, d2): | def get_difficulty_level(d1, d2): | ||||||
|     d = {} |     d = {} | ||||||
|     L = list(d1.keys())  # in d1, we have freuqence for each word |     L = list(d1.keys())  # in d1, we have freuqence for each word | ||||||
|     L2 = list(d2.keys()) # in d2, we have test types (e.g., CET4,CET6,BBC) for each word |     L2 = list(d2.keys())  # in d2, we have test types (e.g., CET4,CET6,BBC) for each word | ||||||
|     L.extend(L2) |     L.extend(L2) | ||||||
|     L3 = list(set(L)) # L3 contains all words |     L3 = list(set(L))  # L3 contains all words | ||||||
|     for k in L3: |     for k in L3: | ||||||
|         if k in d2: |         if k in d2: | ||||||
|             if 'CET4' in d2[k]: |             if 'CET4' in d2[k]: | ||||||
|                 d[k] = 4 # CET4 word has level 4 |                 d[k] = 4  # CET4 word has level 4 | ||||||
|             elif 'CET6' in d2[k]: |             elif 'CET6' in d2[k]: | ||||||
|                 d[k] = 6 |                 d[k] = 6 | ||||||
|             elif 'BBC' in d2[k]: |             elif 'BBC' in d2[k]: | ||||||
|                 d[k] = 8 |                 d[k] = 8 | ||||||
|                 if k in d1: # BBC could contain easy words that are not in CET4 or CET6.  So 4 is not reasonable.  Recompute difficulty level. |                 if k in d1:  # BBC could contain easy words that are not in CET4 or CET6.  So 4 is not reasonable.  Recompute difficulty level. | ||||||
|                     d[k] = min(difficulty_level_from_frequency(k, d1), d[k]) |                     d[k] = min(difficulty_level_from_frequency(k, d1), d[k]) | ||||||
|         elif k in d1: |         elif k in d1: | ||||||
|             d[k] = difficulty_level_from_frequency(k, d1) |             d[k] = difficulty_level_from_frequency(k, d1) | ||||||
|  | @ -52,7 +54,6 @@ def get_difficulty_level(d1, d2): | ||||||
|     return d |     return d | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| def revert_dict(d): | def revert_dict(d): | ||||||
|     ''' |     ''' | ||||||
|     In d, word is the key, and value is a list of dates. |     In d, word is the key, and value is a list of dates. | ||||||
|  | @ -62,12 +63,13 @@ def revert_dict(d): | ||||||
|     for k in d: |     for k in d: | ||||||
|         if type(d[k]) is list:  # d[k] is a list of dates. |         if type(d[k]) is list:  # d[k] is a list of dates. | ||||||
|             lst = d[k] |             lst = d[k] | ||||||
|         elif type(d[k]) is int: # for backward compatibility.  d was sth like {'word':1}.  The value d[k] is not a list of dates, but a number representing how frequent this word had been added to the new word book.  |         elif type(d[ | ||||||
|  |                       k]) is int:  # for backward compatibility.  d was sth like {'word':1}.  The value d[k] is not a list of dates, but a number representing how frequent this word had been added to the new word book. | ||||||
|             freq = d[k] |             freq = d[k] | ||||||
|             lst = freq*['2021082019'] # why choose this date?  No particular reasons.  I fix the bug in this date. |             lst = freq * ['2021082019']  # why choose this date?  No particular reasons.  I fix the bug in this date. | ||||||
| 
 | 
 | ||||||
|         for time_info in lst: |         for time_info in lst: | ||||||
|             date = time_info[:10] # until hour |             date = time_info[:10]  # until hour | ||||||
|             if not date in d2: |             if not date in d2: | ||||||
|                 d2[date] = [k] |                 d2[date] = [k] | ||||||
|             else: |             else: | ||||||
|  | @ -76,42 +78,43 @@ def revert_dict(d): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def user_difficulty_level(d_user, d): | def user_difficulty_level(d_user, d): | ||||||
|     d_user2 = revert_dict(d_user) # key is date, and value is a list of words added in that date |     d_user2 = revert_dict(d_user)  # key is date, and value is a list of words added in that date | ||||||
|     count = 0 |     count = 0 | ||||||
|     geometric = 1 |     geometric = 1 | ||||||
|     for date in sorted(d_user2.keys(), reverse=True): # most recently added words are more important while determining user's level |     for date in sorted(d_user2.keys(), | ||||||
|         lst = d_user2[date] # a list of words |                        reverse=True):  # most recently added words are more important while determining user's level | ||||||
|         lst2 = [] # a list of tuples, (word, difficulty level) |         lst = d_user2[date]  # a list of words | ||||||
|         for  word in lst: |         lst2 = []  # a list of tuples, (word, difficulty level) | ||||||
|  |         for word in lst: | ||||||
|             if word in d: |             if word in d: | ||||||
|                 lst2.append((word, d[word])) |                 lst2.append((word, d[word])) | ||||||
| 
 | 
 | ||||||
|         lst3 = sort_in_ascending_order(lst2) # easiest tuple first |         lst3 = sort_in_ascending_order(lst2)  # easiest tuple first | ||||||
|         #print(lst3) |         # print(lst3) | ||||||
|         for t in lst3: |         for t in lst3: | ||||||
|             word = t[0] |             word = t[0] | ||||||
|             hard = t[1] |             hard = t[1] | ||||||
|             #print('WORD %s HARD %4.2f' % (word, hard)) |             # print('WORD %s HARD %4.2f' % (word, hard)) | ||||||
|             geometric = geometric * (hard) |             geometric = geometric * (hard) | ||||||
|             count += 1 |             count += 1 | ||||||
|             if count >= 10: |             if count >= 10: | ||||||
|                 return geometric**(1/count) |                 return geometric ** (1 / count) | ||||||
| 
 | 
 | ||||||
|     return geometric**(1/max(count,1)) |     return geometric ** (1 / max(count, 1)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def text_difficulty_level(s, d): | def text_difficulty_level(s, d): | ||||||
|     s = remove_punctuation(s) |     s = remove_punctuation(s) | ||||||
|     L = freq(s) |     L = freq(s) | ||||||
| 
 | 
 | ||||||
|     lst = [] # a list of tuples, each tuple being (word, difficulty level) |     lst = []  # a list of tuples, each tuple being (word, difficulty level) | ||||||
|     for x in L: |     for x in L: | ||||||
|         word = x[0] |         word = x[0] | ||||||
|         if word in d: |         if word in d: | ||||||
|             lst.append((word, d[word])) |             lst.append((word, d[word])) | ||||||
| 
 | 
 | ||||||
|     lst2 = sort_in_descending_order(lst) # most difficult words on top |     lst2 = sort_in_descending_order(lst)  # most difficult words on top | ||||||
|     #print(lst2) |     # print(lst2) | ||||||
|     count = 0 |     count = 0 | ||||||
|     geometric = 1 |     geometric = 1 | ||||||
|     for t in lst2: |     for t in lst2: | ||||||
|  | @ -119,22 +122,18 @@ def text_difficulty_level(s, d): | ||||||
|         hard = t[1] |         hard = t[1] | ||||||
|         geometric = geometric * (hard) |         geometric = geometric * (hard) | ||||||
|         count += 1 |         count += 1 | ||||||
|         if count >= 20: # we look for n most difficult words |         if count >= 20:  # we look for n most difficult words | ||||||
|             return geometric**(1/count) |             return geometric ** (1 / count) | ||||||
|          |  | ||||||
|     return geometric**(1/max(count,1)) |  | ||||||
| 
 | 
 | ||||||
|  |     return geometric ** (1 / max(count, 1)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     d1 = load_record('frequency.p') |     d1 = load_record('frequency.p') | ||||||
|     #print(d1) |     # print(d1) | ||||||
| 
 | 
 | ||||||
|     d2 = load_record('words_and_tests.p') |     d2 = load_record('words_and_tests.p') | ||||||
|     #print(d2) |     # print(d2) | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     d3 = get_difficulty_level(d1, d2) |     d3 = get_difficulty_level(d1, d2) | ||||||
| 
 | 
 | ||||||
|  | @ -197,7 +196,6 @@ Amidst the aftermath of this shocking referendum vote, there is great uncertaint | ||||||
| 
 | 
 | ||||||
| ''' | ''' | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     s = ''' |     s = ''' | ||||||
| British Prime Minister Boris Johnson walks towards a voting station during the Brexit referendum in Britain, June 23, 2016. (Photo: EPA-EFE) | British Prime Minister Boris Johnson walks towards a voting station during the Brexit referendum in Britain, June 23, 2016. (Photo: EPA-EFE) | ||||||
| 
 | 
 | ||||||
|  | @ -218,7 +216,6 @@ The prime minister was forced to ask for an extension to Britain's EU departure | ||||||
| Johnson has repeatedly pledged to finalize the first stage, a transition deal, of Britain's EU divorce battle by Oct. 31. A second stage will involve negotiating its future relationship with the EU on trade, security and other salient issues. | Johnson has repeatedly pledged to finalize the first stage, a transition deal, of Britain's EU divorce battle by Oct. 31. A second stage will involve negotiating its future relationship with the EU on trade, security and other salient issues. | ||||||
| ''' | ''' | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     s = ''' |     s = ''' | ||||||
| Thank you very much. We have a Cabinet meeting. We’ll have a few questions after grace. And, if you would, Ben, please do the honors. | Thank you very much. We have a Cabinet meeting. We’ll have a few questions after grace. And, if you would, Ben, please do the honors. | ||||||
| 
 | 
 | ||||||
|  | @ -233,17 +230,9 @@ We need — for our farmers, our manufacturers, for, frankly, unions and non-uni | ||||||
| 
 | 
 | ||||||
| ''' | ''' | ||||||
| 
 | 
 | ||||||
| 
 |     # f = open('bbc-fulltext/bbc/entertainment/001.txt') | ||||||
| 
 |     f = open('wordlist.txt',encoding="utf-8") | ||||||
| 
 |  | ||||||
|     #f = open('bbc-fulltext/bbc/entertainment/001.txt') |  | ||||||
|     f = open('wordlist.txt') |  | ||||||
|     s = f.read() |     s = f.read() | ||||||
|     f.close() |     f.close() | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|      |  | ||||||
|     print(text_difficulty_level(s, d3)) |     print(text_difficulty_level(s, d3)) | ||||||
| 
 |  | ||||||
|              |  | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								app/main.py
								
								
								
								
							
							
						
						
									
										10
									
								
								app/main.py
								
								
								
								
							|  | @ -52,8 +52,7 @@ def appears_in_test(word, d): | ||||||
|     ''' |     ''' | ||||||
|     if not word in d: |     if not word in d: | ||||||
|         return '' |         return '' | ||||||
|     else: |     return ','.join(d[word]) | ||||||
|         return ','.join(d[word]) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.route("/mark", methods=['GET', 'POST']) | @app.route("/mark", methods=['GET', 'POST']) | ||||||
|  | @ -71,8 +70,8 @@ def mark_word(): | ||||||
|         d = pickle_idea.merge_frequency(lst, lst_history) |         d = pickle_idea.merge_frequency(lst, lst_history) | ||||||
|         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') |         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') | ||||||
|         return redirect(url_for('mainpage')) |         return redirect(url_for('mainpage')) | ||||||
|     else: # 不回应GET请求 |     # 不回应GET请求 | ||||||
|         return 'Under construction' |     return 'Under construction' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.route("/", methods=['GET', 'POST']) | @app.route("/", methods=['GET', 'POST']) | ||||||
|  | @ -92,7 +91,7 @@ def mainpage(): | ||||||
|         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') |         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') | ||||||
|         return render_template('mainpage_post.html', lst=lst, yml=Yaml.yml) |         return render_template('mainpage_post.html', lst=lst, yml=Yaml.yml) | ||||||
| 
 | 
 | ||||||
|     elif request.method == 'GET':  # when we load a html page |     if request.method == 'GET':  # when we load a html page | ||||||
|         random_ads = get_random_ads() |         random_ads = get_random_ads() | ||||||
|         number_of_essays = total_number_of_essays() |         number_of_essays = total_number_of_essays() | ||||||
|         d = load_freq_history(path_prefix + 'static/frequency/frequency.p') |         d = load_freq_history(path_prefix + 'static/frequency/frequency.p') | ||||||
|  | @ -102,7 +101,6 @@ def mainpage(): | ||||||
|                                d_len=d_len, lst=lst, yml=Yaml.yml) |                                d_len=d_len, lst=lst, yml=Yaml.yml) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     ''' |     ''' | ||||||
|     运行程序 |     运行程序 | ||||||
|  |  | ||||||
|  | @ -3,9 +3,10 @@ | ||||||
| # Written permission must be obtained from the author for commercial uses. | # Written permission must be obtained from the author for commercial uses. | ||||||
| ########################################################################### | ########################################################################### | ||||||
| 
 | 
 | ||||||
| # Purpose: dictionary & pickle as a simple means of database. | """ | ||||||
| # Task: incorporate the functions into wordfreqCMD.py such that it will also show cumulative frequency. |   Purpose: dictionary & pickle as a simple means of database. | ||||||
| 
 |   Task: incorporate the functions into wordfreqCMD.py such that it will also show cumulative frequency. | ||||||
|  | """ | ||||||
| import pickle | import pickle | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ def dict2lst(d): | ||||||
|             for k in d: |             for k in d: | ||||||
|                 lst.append((k, [datetime.now().strftime('%Y%m%d%H%M')])) |                 lst.append((k, [datetime.now().strftime('%Y%m%d%H%M')])) | ||||||
|             return lst |             return lst | ||||||
|         elif isinstance(d[keys[0]], list): |         if isinstance(d[keys[0]], list): | ||||||
|             return list(d.items()) # a list of (key, value) pairs |             return list(d.items()) # a list of (key, value) pairs | ||||||
| 
 | 
 | ||||||
|     return [] |     return [] | ||||||
|  |  | ||||||
|  | @ -11,34 +11,39 @@ function getWord() { | ||||||
| 
 | 
 | ||||||
| function fillInWord() { | function fillInWord() { | ||||||
|     let word = getWord(); |     let word = getWord(); | ||||||
|     if (isRead) read(word); |     if (isRead) {read(word);} | ||||||
|     if (!isChoose) return; |     if (!isChoose) {return;} | ||||||
|     const element = document.getElementById("selected-words"); |     const element = document.getElementById("selected-words"); | ||||||
|     element.value = element.value + " " + word; |     element.value = element.value + " " + word; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| document.getElementById("text-content").addEventListener("click", fillInWord, false); | document | ||||||
|  |     .getElementById("text-content") | ||||||
|  |     .addEventListener("click", fillInWord, false); | ||||||
| 
 | 
 | ||||||
| function makeUtterance(str, rate) { | function makeUtterance(str, rate) { | ||||||
|     let msg = new SpeechSynthesisUtterance(str); |     let msg = new SpeechSynthesisUtterance(str); | ||||||
|     msg.rate = rate; |     msg.rate = rate; | ||||||
|     msg.lang = "en-US"; // TODO: add language options menu
 |     msg.lang = "en-US"; // TODO: add language options menu
 | ||||||
|     msg.onboundary = ev => { |     msg.onboundary = function(ev) { | ||||||
|         if (ev.name == "word") { |         if (ev.name === "word") { | ||||||
|             current_position = ev.charIndex; |             current_position = ev.charIndex; | ||||||
|         } |         } | ||||||
|     } |     }; | ||||||
|     return msg; |     return msg; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const sliderValue = document.getElementById("rangeValue"); // 显示值
 | const sliderValue = document.getElementById("rangeValue"); // 显示值
 | ||||||
| const inputSlider = document.getElementById("rangeComponent"); // 滑块元素
 | const inputSlider = document.getElementById("rangeComponent"); // 滑块元素
 | ||||||
| inputSlider.oninput = () => { | inputSlider.oninput = function(){ | ||||||
|     let value = inputSlider.value; // 获取滑块的值
 |     let value = inputSlider.value; // 获取滑块的值
 | ||||||
|     sliderValue.textContent = value + '×'; |     sliderValue.textContent = value + "×"; | ||||||
|     if (!reader.speaking) return; |     if (!reader.speaking) {return;} | ||||||
|     reader.cancel(); |     reader.cancel(); | ||||||
|     let msg = makeUtterance(to_speak.substring(original_position + current_position), value); |     let msg = makeUtterance( | ||||||
|  |         to_speak.substring(original_position + current_position), | ||||||
|  |         value | ||||||
|  |     ); | ||||||
|     original_position = original_position + current_position; |     original_position = original_position + current_position; | ||||||
|     current_position = 0; |     current_position = 0; | ||||||
|     reader.speak(msg); |     reader.speak(msg); | ||||||
|  |  | ||||||
|  | @ -2,44 +2,60 @@ let isHighlight = true; | ||||||
| 
 | 
 | ||||||
| function cancelBtnHandler() { | function cancelBtnHandler() { | ||||||
|     cancelHighlighting(); |     cancelHighlighting(); | ||||||
|     document.getElementById("text-content").removeEventListener("click", fillInWord, false); |     document | ||||||
|     document.getElementById("text-content").removeEventListener("touchstart", fillInWord, false); |         .getElementById("text-content") | ||||||
|     document.getElementById("text-content").addEventListener("click", fillInWord2, false); |         .removeEventListener("click", fillInWord, false); | ||||||
|     document.getElementById("text-content").addEventListener("touchstart", fillInWord2, false); |     document.getElementById("text-content") | ||||||
|  |         .removeEventListener("touchstart", fillInWord, false); | ||||||
|  |     document.getElementById("text-content") | ||||||
|  |         .addEventListener("click", fillInWord2, false); | ||||||
|  |     document.getElementById("text-content") | ||||||
|  |         .addEventListener("touchstart", fillInWord2, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function showBtnHandler() { | function showBtnHandler() { | ||||||
|     document.getElementById("text-content").removeEventListener("click", fillInWord2, false); |     document.getElementById("text-content") | ||||||
|     document.getElementById("text-content").removeEventListener("touchstart", fillInWord2, false); |         .removeEventListener("click", fillInWord2, false); | ||||||
|     document.getElementById("text-content").addEventListener("click", fillInWord, false); |     document.getElementById("text-content") | ||||||
|     document.getElementById("text-content").addEventListener("touchstart", fillInWord, false); |         .removeEventListener("touchstart", fillInWord2, false); | ||||||
|  |     document.getElementById("text-content") | ||||||
|  |         .addEventListener("click", fillInWord, false); | ||||||
|  |     document.getElementById("text-content") | ||||||
|  |         .addEventListener("touchstart", fillInWord, false); | ||||||
|     highLight(); |     highLight(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getWord() { | function getWord() { | ||||||
|     return window.getSelection ? window.getSelection() : document.selection.createRange().text; |     return (window.getSelection ? | ||||||
|  |             window.getSelection() : | ||||||
|  |             document.selection.createRange().text); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function highLight() { | function highLight() { | ||||||
|     if (!isHighlight) return; |     if (!isHighlight) {return;} | ||||||
|     let articleContent = document.getElementById("article").innerText; //将原来的.innerText改为.innerHtml,使用innerText会把原文章中所包含的<br>标签去除,导致处理后的文章内容失去了原来的格式
 |     let articleContent = document.getElementById("article").innerText; //将原来的.innerText改为.innerHtml,使用innerText会把原文章中所包含的<br>标签去除,导致处理后的文章内容失去了原来的格式
 | ||||||
|     let pickedWords = document.getElementById("selected-words");  // words picked to the text area
 |     let pickedWords = document.getElementById("selected-words");  // words picked to the text area
 | ||||||
|     let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
 |     let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
 | ||||||
|     let allWords = "";  //初始化allWords的值,避免进入判断后编译器认为allWords未初始化的问题
 |     let allWords = "";  //初始化allWords的值,避免进入判断后编译器认为allWords未初始化的问题
 | ||||||
|     if(dictionaryWords != null){//增加一个判断,检查生词本里面是否为空,如果为空,allWords只添加选中的单词
 |     if(dictionaryWords !== null){//增加一个判断,检查生词本里面是否为空,如果为空,allWords只添加选中的单词
 | ||||||
|         allWords = pickedWords.value + " " + dictionaryWords.value; |         allWords = pickedWords.value + " " + dictionaryWords.value; | ||||||
|     } |     } | ||||||
|     else{ |     else{ | ||||||
|         allWords = pickedWords.value + " "; |         allWords = pickedWords.value + " "; | ||||||
|     } |     } | ||||||
|     const list = allWords.split(" ");//将所有的生词放入一个list中,用于后续处理
 |     const list = allWords.split(" ");//将所有的生词放入一个list中,用于后续处理
 | ||||||
|     for (let i = 0; i < list.length; ++i) { |     for (let i = 0; i < list.length; i+=1) { | ||||||
|         list[i] = list[i].replace(/(^\s*)|(\s*$)/g, ""); //消除单词两边的空字符
 |         list[i] = list[i].replace(/(^\s*)|(\s*$)/gm, ""); //消除单词两边的空字符
 | ||||||
|         list[i] = list[i].replace('|', ""); |         list[i] = list[i].replace("|", ""); | ||||||
|         list[i] = list[i].replace('?', ""); |         list[i] = list[i].replace("?", ""); | ||||||
|         if (list[i] !== "" && "<mark>".indexOf(list[i]) === -1 && "</mark>".indexOf(list[i]) === -1) { |         if (list[i] !== "" && | ||||||
| 	    //将文章中所有出现该单词word的地方改为:" <mark>" + word + "<mark> "。 正则表达式RegExp()中,"\\s"代表单词前后必须要有空格,以防止只对单词中的部分字符高亮的情况出现。
 |             "<mark>".indexOf(list[i]) === -1 && | ||||||
|             articleContent = articleContent.replace(new RegExp("\\s"+list[i]+"\\s", "g"), " <mark>" + list[i] + "</mark> "); |             "</mark>".indexOf(list[i]) === -1 | ||||||
|  |            ) { | ||||||
|  |         //将文章中所有出现该单词word的地方改为:" <mark>" + word + "<mark> "。 正则表达式RegExp()中,"\\s"代表单词前后必须要有空格,以防止只对单词中的部分字符高亮的情况出现。
 | ||||||
|  |             articleContent = articleContent.replace( | ||||||
|  |                 new RegExp("\\s"+list[i]+"\\s", "g"), | ||||||
|  |                 " <mark>" + list[i] + "</mark> "); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     document.getElementById("article").innerHTML = articleContent; |     document.getElementById("article").innerHTML = articleContent; | ||||||
|  | @ -50,21 +66,27 @@ function cancelHighlighting() { | ||||||
|     let pickedWords = document.getElementById("selected-words"); |     let pickedWords = document.getElementById("selected-words"); | ||||||
|     const dictionaryWords = document.getElementById("selected-words2"); |     const dictionaryWords = document.getElementById("selected-words2"); | ||||||
|     const list = pickedWords.value.split(" "); |     const list = pickedWords.value.split(" "); | ||||||
|     if (pickedWords != null) { |     if (pickedWords !== null) { | ||||||
|         for (let i = 0; i < list.length; ++i) { |         for (let i = 0; i < list.length; i+=1) { | ||||||
|             list[i] = list[i].replace(/(^\s*)|(\s*$)/g, ""); |             list[i] = list[i].replace(/(^\s*)|(\s*$)/gm, ""); | ||||||
|             if (list[i] !== "") { //原来判断的代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
 |             if (list[i] !== "") { //原来判断的代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
 | ||||||
|                 articleContent = articleContent.replace(new RegExp("<mark>"+list[i]+"</mark>", "g"), list[i]); |                 articleContent = articleContent.replace( | ||||||
|  |                     new RegExp("<mark>"+list[i]+"</mark>", "g"), | ||||||
|  |                     list[i] | ||||||
|  |                 ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (dictionaryWords != null) { |     if (dictionaryWords !== null) { | ||||||
|         let list2 = pickedWords.value.split(" "); |         let list2 = pickedWords.value.split(" "); | ||||||
|         for (let i = 0; i < list2.length; ++i) { |         for (let i = 0; i < list2.length; i+=1) { | ||||||
|             list2 = dictionaryWords.value.split(" "); |             list2 = dictionaryWords.value.split(" "); | ||||||
|             list2[i] = list2[i].replace(/(^\s*)|(\s*$)/g, ""); |             list2[i] = list2[i].replace(/(^\s*)|(\s*$)/gm, ""); | ||||||
|             if (list2[i] !== "") { //原来代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
 |             if (list2[i] !== "") { //原来代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
 | ||||||
|                 articleContent = articleContent.replace(new RegExp("<mark>"+list2[i]+"</mark>", "g"), list2[i]); |                 articleContent = articleContent.replace( | ||||||
|  |                     new RegExp("<mark>"+list2[i]+"</mark>", "g"), | ||||||
|  |                     list2[i] | ||||||
|  |                 ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -3,17 +3,17 @@ function familiar(theWord) { | ||||||
|     let word = $("#word_" + theWord).text(); |     let word = $("#word_" + theWord).text(); | ||||||
|     let freq = $("#freq_" + theWord).text(); |     let freq = $("#freq_" + theWord).text(); | ||||||
|     $.ajax({ |     $.ajax({ | ||||||
|         type:"GET", |  | ||||||
|         url:"/" + username + "/" + word + "/familiar", |  | ||||||
|         success:function(response){ |         success:function(response){ | ||||||
|             let new_freq = freq - 1; |             let new_freq = freq - 1; | ||||||
|             const allow_move = document.getElementById("move_dynamiclly").checked; |             const allow_move = document | ||||||
|  |                 .getElementById("move_dynamiclly") | ||||||
|  |                 .checked; | ||||||
|             if (allow_move) { |             if (allow_move) { | ||||||
| 
 | 
 | ||||||
|                 if (new_freq <= 0) { |                 if (new_freq <= 0) { | ||||||
|                     removeWord(theWord); |                     removeWord(theWord); | ||||||
|                 } else { |                 } else { | ||||||
|                     renderWord({ word: theWord, freq: new_freq }); |                     renderWord({ freq: new_freq,word: theWord }); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if(new_freq <1) { |                 if(new_freq <1) { | ||||||
|  | @ -22,7 +22,9 @@ function familiar(theWord) { | ||||||
|                     $("#freq_" + theWord).text(new_freq); |                     $("#freq_" + theWord).text(new_freq); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         }, | ||||||
|  |         type:"GET", | ||||||
|  |         url:"/" + username + "/" + word + "/familiar" | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -31,34 +33,38 @@ function unfamiliar(theWord) { | ||||||
|     let word = $("#word_" + theWord).text(); |     let word = $("#word_" + theWord).text(); | ||||||
|     let freq = $("#freq_" + theWord).text(); |     let freq = $("#freq_" + theWord).text(); | ||||||
|     $.ajax({ |     $.ajax({ | ||||||
|         type:"GET", |  | ||||||
|         url:"/" + username + "/" + word + "/unfamiliar", |  | ||||||
|         success:function(response){ |         success:function(response){ | ||||||
|             let new_freq = parseInt(freq) + 1; |             let new_freq = parseInt(freq) + 1; | ||||||
|             const allow_move = document.getElementById("move_dynamiclly").checked; |             const allow_move = document | ||||||
|  |                 .getElementById("move_dynamiclly") | ||||||
|  |                 .checked; | ||||||
|             if (allow_move) { |             if (allow_move) { | ||||||
|                 renderWord({ word: theWord, freq: new_freq }); |                 renderWord({ freq: new_freq,word: theWord  }); | ||||||
|             } else { |             } else { | ||||||
|                 $("#freq_" + theWord).text(new_freq); |                 $("#freq_" + theWord).text(new_freq); | ||||||
|             } |             } | ||||||
|         } |         }, | ||||||
|  |         type:"GET", | ||||||
|  |         url:"/" + username + "/" + word + "/unfamiliar" | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function delete_word(theWord) { | function delete_word(theWord) { | ||||||
|     let username = $("#username").text(); |     let username = $("#username").text(); | ||||||
|     let word = theWord.replace('&', '&'); |     let word = theWord.replace("&", "&"); | ||||||
|     $.ajax({ |     $.ajax({ | ||||||
|         type:"GET", |  | ||||||
|         url:"/" + username + "/" + word + "/del", |  | ||||||
|         success:function(response){ |         success:function(response){ | ||||||
|             const allow_move = document.getElementById("move_dynamiclly").checked; |             const allow_move = document | ||||||
|  |                 .getElementById("move_dynamiclly") | ||||||
|  |                 .checked; | ||||||
|             if (allow_move) { |             if (allow_move) { | ||||||
|                 removeWord(theWord); |                 removeWord(theWord); | ||||||
|             } else { |             } else { | ||||||
|                 $("#p_" + theWord).remove(); |                 $("#p_" + theWord).remove(); | ||||||
|             } |             } | ||||||
|         } |         }, | ||||||
|  |         type:"GET", | ||||||
|  |         url:"/" + username + "/" + word + "/del" | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -75,11 +81,12 @@ function delete_word(theWord) { | ||||||
| function parseWord(element) { | function parseWord(element) { | ||||||
|     const word = element |     const word = element | ||||||
|         .querySelector("a.btn.btn-light[role=button]")  // 获取当前词频元素的词汇元素
 |         .querySelector("a.btn.btn-light[role=button]")  // 获取当前词频元素的词汇元素
 | ||||||
|         .innerText  // 获取词汇值;
 |         .innerText; // 获取词汇值;
 | ||||||
|     const freq = Number.parseInt(element.querySelector(`#freq_${word}`).innerText);   // 获取词汇的数量
 |     const freq = Number// 获取词汇的数量
 | ||||||
|  |         .parseInt(element.querySelector(`#freq_${word}`).innerText); | ||||||
|     return { |     return { | ||||||
|         word, |         freq, | ||||||
|         freq |         word | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -104,7 +111,7 @@ function wordTemplate(word) { | ||||||
|  */ |  */ | ||||||
| function removeWord(word) { | function removeWord(word) { | ||||||
|     // 根据词频信息删除元素
 |     // 根据词频信息删除元素
 | ||||||
|     word = word.replace('&', '&'); |     word = word.replace("&", "&"); | ||||||
|     const element_to_remove = document.getElementById(`p_${word}`); |     const element_to_remove = document.getElementById(`p_${word}`); | ||||||
|     if (element_to_remove != null) { |     if (element_to_remove != null) { | ||||||
|         element_to_remove.remove(); |         element_to_remove.remove(); | ||||||
|  | @ -134,7 +141,11 @@ function renderWord(word) { | ||||||
|     // 让发生变化的元素抖动
 |     // 让发生变化的元素抖动
 | ||||||
|     new_element.classList.add("shaking"); |     new_element.classList.add("shaking"); | ||||||
|     // 移动到该元素
 |     // 移动到该元素
 | ||||||
|     new_element.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"}); |     new_element.scrollIntoView({ | ||||||
|  |         behavior: "smooth", | ||||||
|  |         block: "center", | ||||||
|  |         inline: "nearest" | ||||||
|  |     }); | ||||||
|     // 抖动完毕后删除抖动类
 |     // 抖动完毕后删除抖动类
 | ||||||
|     setTimeout(() => { |     setTimeout(() => { | ||||||
|         new_element.classList.remove("shaking"); |         new_element.classList.remove("shaking"); | ||||||
|  | @ -145,7 +156,7 @@ function renderWord(word) { | ||||||
|  * 从string中创建一个HTML元素并返回 |  * 从string中创建一个HTML元素并返回 | ||||||
|  */ |  */ | ||||||
| function elementFromString(string) { | function elementFromString(string) { | ||||||
|     const d = document.createElement('div'); |     const d = document.createElement("div"); | ||||||
|     d.innerHTML = string; |     d.innerHTML = string; | ||||||
|     return d.children.item(0); |     return d.children.item(0); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
|  | """ | ||||||
|  | This module provides methods for user_services | ||||||
|  | """ | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 |  | ||||||
| from flask import * | from flask import * | ||||||
| 
 | 
 | ||||||
| # from app import Yaml | # from app import Yaml | ||||||
|  | @ -36,6 +38,7 @@ def user_reset(username): | ||||||
|     else: |     else: | ||||||
|         return 'Under construction' |         return 'Under construction' | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| @userService.route("/<username>/back", methods=['GET']) | @userService.route("/<username>/back", methods=['GET']) | ||||||
| def user_back(username): | def user_back(username): | ||||||
|     ''' |     ''' | ||||||
|  | @ -48,7 +51,6 @@ def user_back(username): | ||||||
|         return redirect(url_for('user_bp.userpage', username=username)) |         return redirect(url_for('user_bp.userpage', username=username)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @userService.route("/<username>/<word>/unfamiliar", methods=['GET', 'POST']) | @userService.route("/<username>/<word>/unfamiliar", methods=['GET', 'POST']) | ||||||
| def unfamiliar(username, word): | def unfamiliar(username, word): | ||||||
|     ''' |     ''' | ||||||
|  | @ -141,9 +143,6 @@ def userpage(username): | ||||||
|                                words=words) |                                words=words) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @userService.route("/<username>/mark", methods=['GET', 'POST']) | @userService.route("/<username>/mark", methods=['GET', 'POST']) | ||||||
| def user_mark_word(username): | def user_mark_word(username): | ||||||
|     ''' |     ''' | ||||||
|  |  | ||||||
|  | @ -2,13 +2,16 @@ | ||||||
| # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | ||||||
| # Written permission must be obtained from the author for commercial uses. | # Written permission must be obtained from the author for commercial uses. | ||||||
| ########################################################################### | ########################################################################### | ||||||
| 
 | """ | ||||||
|  | This Module produces word frequency | ||||||
|  | """ | ||||||
| import collections | import collections | ||||||
| import string | import string | ||||||
| import operator | import operator | ||||||
| import os, sys # 引入模块sys,因为我要用里面的sys.argv列表中的信息来读取命令行参数。 | import os, sys  # 引入模块sys,因为我要用里面的sys.argv列表中的信息来读取命令行参数。 | ||||||
| import pickle_idea | import pickle_idea | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def freq(fruit): | def freq(fruit): | ||||||
|     ''' |     ''' | ||||||
|     功能: 把字符串转成列表。 目的是得到每个单词的频率。 |     功能: 把字符串转成列表。 目的是得到每个单词的频率。 | ||||||
|  | @ -18,40 +21,39 @@ def freq(fruit): | ||||||
|     ''' |     ''' | ||||||
| 
 | 
 | ||||||
|     result = [] |     result = [] | ||||||
|      |     fruit = fruit.lower()  # 字母转小写 | ||||||
|     fruit = fruit.lower() # 字母转小写 |  | ||||||
|     flst = fruit.split()  # 字符串转成list |     flst = fruit.split()  # 字符串转成list | ||||||
|     c = collections.Counter(flst) |     c = collections.Counter(flst) | ||||||
|     result = c.most_common() |     result = c.most_common() | ||||||
|     return result |     return result | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def youdao_link(s): # 有道链接 | def youdao_link(s):  # 有道链接 | ||||||
|     link = 'http://youdao.com/w/eng/' + s + '/#keyfrom=dict2.index'# 网址 |     link = 'http://youdao.com/w/eng/' + s + '/#keyfrom=dict2.index'  # 网址 | ||||||
|     return link |     return link | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def file2str(fname):#文件转字符 | def file2str(fname):  # 文件转字符 | ||||||
|     f = open(fname) #打开 |     f = open(fname)  # 打开 | ||||||
|     s = f.read()    #读取 |     s = f.read()  # 读取 | ||||||
|     f.close()       #关闭 |     f.close()  # 关闭 | ||||||
|     return s |     return s | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def remove_punctuation(s): # 这里是s是形参 (parameter)。函数被调用时才给s赋值。 | def remove_punctuation(s):  # 这里是s是形参 (parameter)。函数被调用时才给s赋值。 | ||||||
|     special_characters = '\_©~<=>+-/[]*&$%^@.,?!:;#()"“”—‘’{}|' # 把里面的字符都去掉 |     special_characters = '\_©~<=>+-/[]*&$%^@.,?!:;#()"“”—‘’{}|'  # 把里面的字符都去掉 | ||||||
|     for c in special_characters: |     for c in special_characters: | ||||||
|         s = s.replace(c, ' ') # 防止出现把 apple,apple 移掉逗号后变成 appleapple 情况 |         s = s.replace(c, ' ')  # 防止出现把 apple,apple 移掉逗号后变成 appleapple 情况 | ||||||
|     s = s.replace('--', ' ') |     s = s.replace('--', ' ') | ||||||
|     s = s.strip() # 去除前后的空格 |     s = s.strip()  # 去除前后的空格 | ||||||
| 
 | 
 | ||||||
|     if '\'' in s: |     if '\'' in s: | ||||||
|         n = len(s) |         n = len(s) | ||||||
|         t = '' # 用来收集我需要保留的字符 |         t = ''  # 用来收集我需要保留的字符 | ||||||
|         for i in range(n): # 只有单引号前后都有英文字符,才保留 |         for i in range(n):  # 只有单引号前后都有英文字符,才保留 | ||||||
|             if s[i] == '\'': |             if s[i] == '\'': | ||||||
|                 i_is_ok = i - 1 >= 0 and i + 1 < n |                 i_is_ok = i - 1 >= 0 and i + 1 < n | ||||||
|                 if i_is_ok and s[i-1] in string.ascii_letters and s[i+1] in string.ascii_letters: |                 if i_is_ok and s[i - 1] in string.ascii_letters and s[i + 1] in string.ascii_letters: | ||||||
|                     t += s[i] |                     t += s[i] | ||||||
|             else: |             else: | ||||||
|                 t += s[i] |                 t += s[i] | ||||||
|  | @ -60,12 +62,12 @@ def remove_punctuation(s): # 这里是s是形参 (parameter)。函数被调用 | ||||||
|         return s |         return s | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def sort_in_descending_order(lst):# 单词按频率降序排列 | def sort_in_descending_order(lst):  # 单词按频率降序排列 | ||||||
|     lst2 = sorted(lst, reverse=True, key=lambda x: (x[1], x[0])) |     lst2 = sorted(lst, reverse=True, key=lambda x: (x[1], x[0])) | ||||||
|     return lst2 |     return lst2 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def sort_in_ascending_order(lst):# 单词按频率降序排列 | def sort_in_ascending_order(lst):  # 单词按频率降序排列 | ||||||
|     lst2 = sorted(lst, reverse=False, key=lambda x: (x[1], x[0])) |     lst2 = sorted(lst, reverse=False, key=lambda x: (x[1], x[0])) | ||||||
|     return lst2 |     return lst2 | ||||||
| 
 | 
 | ||||||
|  | @ -85,39 +87,30 @@ def make_html_page(lst, fname): | ||||||
|     f.close() |     f.close() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## main(程序入口) | # main(程序入口) | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     num = len(sys.argv) |     num = len(sys.argv) | ||||||
| 
 |     if num == 1:  # 从键盘读入字符串 | ||||||
|     if num == 1: # 从键盘读入字符串 |  | ||||||
|         s = input() |         s = input() | ||||||
|     elif num == 2: # 从文件读入字符串 |     elif num == 2:  # 从文件读入字符串 | ||||||
|         fname = sys.argv[1] |         fname = sys.argv[1] | ||||||
|         s = file2str(fname) |         s = file2str(fname) | ||||||
|     else: |     else: | ||||||
|         print('I can accept at most 2 arguments.') |         print('I can accept at most 2 arguments.') | ||||||
|         sys.exit()# 结束程序运行, 下面的代码不会被执行了。 |         sys.exit()  # 结束程序运行, 下面的代码不会被执行了。 | ||||||
| 
 |     s = remove_punctuation(s)  # 这里是s是实参(argument),里面有值 | ||||||
|     s = remove_punctuation(s) # 这里是s是实参(argument),里面有值 |  | ||||||
|     L = freq(s) |     L = freq(s) | ||||||
|     for x in sort_in_descending_order(L): |     for x in sort_in_descending_order(L): | ||||||
|         print('%s\t%d\t%s' % (x[0], x[1], youdao_link(x[0])))#函数导出 |         print('%s\t%d\t%s' % (x[0], x[1], youdao_link(x[0])))  # 函数导出 | ||||||
| 
 |  | ||||||
|     # 把频率的结果放result.html中 |     # 把频率的结果放result.html中 | ||||||
|     make_html_page(sort_in_descending_order(L), 'result.html') |     make_html_page(sort_in_descending_order(L), 'result.html') | ||||||
| 
 |  | ||||||
|     print('\nHistory:\n') |     print('\nHistory:\n') | ||||||
|     if os.path.exists('frequency.p'): |     if os.path.exists('frequency.p'): | ||||||
|         d = pickle_idea.load_record('frequency.p') |         d = pickle_idea.load_record('frequency.p') | ||||||
|     else: |     else: | ||||||
|         d = {} |         d = {} | ||||||
| 
 |  | ||||||
|     print(sort_in_descending_order(pickle_idea.dict2lst(d))) |     print(sort_in_descending_order(pickle_idea.dict2lst(d))) | ||||||
| 
 |  | ||||||
|     # 合并频率 |     # 合并频率 | ||||||
|     lst_history = pickle_idea.dict2lst(d) |     lst_history = pickle_idea.dict2lst(d) | ||||||
|     d = pickle_idea.merge_frequency(L, lst_history) |     d = pickle_idea.merge_frequency(L, lst_history) | ||||||
|     pickle_idea.save_frequency_to_pickle(d, 'frequency.p') |     pickle_idea.save_frequency_to_pickle(d, 'frequency.p') | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue