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 wordfreqCMD import youdao_link, sort_in_descending_order | ||||
| 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') | ||||
|     d2 = load_freq_history(path_prefix + 'static/words_and_tests.p') | ||||
|     d3 = get_difficulty_level(d1, d2) | ||||
| 
 | ||||
|     d = {} | ||||
|     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. | ||||
|  |  | |||
							
								
								
									
										29
									
								
								app/Login.py
								
								
								
								
							
							
						
						
									
										29
									
								
								app/Login.py
								
								
								
								
							|  | @ -1,3 +1,6 @@ | |||
| """ | ||||
| This module provides methods for Login | ||||
| """ | ||||
| import hashlib | ||||
| import string | ||||
| from datetime import datetime, timedelta | ||||
|  | @ -7,15 +10,17 @@ path_prefix = '/var/www/wordfreq/wordfreq/' | |||
| path_prefix = './'  # comment this line in deployment | ||||
| 
 | ||||
| def verify_pass(newpass,oldpass): | ||||
|     if(newpass==oldpass): | ||||
|     if newpass==oldpass: | ||||
|         return True | ||||
| 
 | ||||
| 
 | ||||
| def verify_user(username, password): | ||||
|     rq = RecordQuery(path_prefix + 'static/wordfreqapp.db') | ||||
|     password = md5(username + password) | ||||
|     rq.instructions_with_parameters("SELECT * FROM user WHERE name=:username AND password=:password", dict( | ||||
|         username=username, password=password))  # the named style https://docs.python.org/3/library/sqlite3.html | ||||
|     rq.instructions_with_parameters( | ||||
|         "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() | ||||
|     result = rq.get_results() | ||||
|     return result != [] | ||||
|  | @ -23,12 +28,19 @@ def verify_user(username, password): | |||
| 
 | ||||
| def add_user(username, password): | ||||
|     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) | ||||
|     rq = InsertQuery(path_prefix + 'static/wordfreqapp.db') | ||||
|     rq.instructions_with_parameters("INSERT INTO user VALUES (:username, :password, :start_date, :expiry_date)", dict( | ||||
|         username=username, password=password, start_date=start_date, expiry_date=expiry_date)) | ||||
|     rq.instructions_with_parameters( | ||||
|         "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() | ||||
| 
 | ||||
| 
 | ||||
|  | @ -96,7 +108,7 @@ class UserName: | |||
|         if ' ' in self.username: # a user name must not include a whitespace | ||||
|             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 | ||||
|             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.' | ||||
|         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.' | ||||
|  | @ -110,4 +122,3 @@ class WarningMessage: | |||
| 
 | ||||
|     def __str__(self): | ||||
|         return UserName(self.s).validate() | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,9 +2,12 @@ | |||
| # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | ||||
| # 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 | ||||
| from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order | ||||
| 
 | ||||
| 
 | ||||
| class WordFreq: | ||||
|     def __init__(self, s): | ||||
|  | @ -22,4 +25,3 @@ class WordFreq: | |||
| if __name__ == '__main__': | ||||
|     f = WordFreq('BANANA; Banana, apple ORANGE Banana banana.') | ||||
|     print(f.get_freq()) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,41 +1,43 @@ | |||
| """ | ||||
| This module provides services about account. | ||||
| """ | ||||
| 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__) | ||||
| 
 | ||||
| ### Sign-up, login, logout ### | ||||
| 
 | ||||
| # Sign-up, login, logout | ||||
| @accountService.route("/signup", methods=['GET', 'POST']) | ||||
| def signup(): | ||||
|     ''' | ||||
|     注册 | ||||
|     :return: 根据注册是否成功返回不同界面 | ||||
|     ''' | ||||
|     if request.method == 'GET': | ||||
|     # GET方法直接返回注册页面 | ||||
|     if request.method == 'GET': | ||||
|         return render_template('signup.html') | ||||
|     elif request.method == 'POST': | ||||
|     if request.method == 'POST': | ||||
|         # POST方法需判断是否注册成功,再根据结果返回不同的内容 | ||||
|         username = escape(request.form['username']) | ||||
|         password = escape(request.form['password']) | ||||
|         password2 = escape(request.form['password2']) | ||||
|          | ||||
|         #! 添加如下代码为了过滤注册时的非法字符 | ||||
|         warn = WarningMessage(username) | ||||
|         if str(warn) != 'OK': | ||||
|             return str(warn) | ||||
|          | ||||
|         available = check_username_availability(username) | ||||
|         if not available: # 用户名不可用 | ||||
|             flash('用户名 %s 已经被注册。' % (username)) | ||||
|             return render_template('signup.html') | ||||
|         elif len(password.strip()) < 4: # 密码过短 | ||||
|         if len(password.strip()) < 4: # 密码过短 | ||||
|             return '密码过于简单。' | ||||
|         elif password != password2: | ||||
|         if password != password2: | ||||
|             return '确认密码与输入密码不一致!' | ||||
|         else: # 添加账户信息 | ||||
|             add_user(username, password) | ||||
|         add_user(username, password)# 添加账户信息 | ||||
|         verified = verify_user(username, password) | ||||
|         if verified: | ||||
|             # 写入session | ||||
|  | @ -46,11 +48,9 @@ def signup(): | |||
|             session['articleID'] = None | ||||
|             return '<p>恭喜,你已成功注册, 你的用户名是 <a href="%s">%s</a>。</p>\ | ||||
|             <p><a href="/%s">开始使用</a> <a href="/">返回首页</a><p/>' % (username, username, username) | ||||
|             else: | ||||
|         return '用户名密码验证失败。' | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @accountService.route("/login", methods=['GET', 'POST']) | ||||
| def login(): | ||||
|     ''' | ||||
|  | @ -62,11 +62,10 @@ def login(): | |||
|         if not session.get('logged_in'): | ||||
|             # 未登录,返回登录页面 | ||||
|             return render_template('login.html') | ||||
|         else: | ||||
|         # 已登录,提示信息并显示登出按钮 | ||||
|         return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % ( | ||||
|                 session['username'], session['username']) | ||||
|     elif request.method == 'POST': | ||||
|     if request.method == 'POST': | ||||
|         # POST方法用于判断登录是否成功 | ||||
|         # check database and verify user | ||||
|         username = escape(request.form['username']) | ||||
|  | @ -81,7 +80,6 @@ def login(): | |||
|             session['expiry_date'] = user_expiry_date | ||||
|             session['articleID'] = None | ||||
|             return redirect(url_for('user_bp.userpage', username=username)) | ||||
|         else: | ||||
|         return '无法通过验证。' | ||||
| 
 | ||||
| 
 | ||||
|  | @ -111,17 +109,14 @@ def reset(): | |||
|     if request.method == 'GET': | ||||
|         # GET请求返回修改密码页面 | ||||
|         return render_template('reset.html', username=session['username'], state='wait') | ||||
|     else: | ||||
|     # POST请求用于提交修改后信息 | ||||
|     old_password = escape(request.form['old-password']) | ||||
|     new_password = escape(request.form['new-password']) | ||||
| 
 | ||||
|     re_new_password = escape(request.form['re-new-password'])  # 确认新密码 | ||||
|     if re_new_password != new_password: #验证新密码两次输入是否相同 | ||||
|         return '新密码不匹配,请重新输入' | ||||
|     if len(new_password) < 4: #验证新密码长度,原则参照注册模块 | ||||
|         return '密码过于简单。(密码长度至少4位)' | ||||
| 
 | ||||
|     flag = change_password(username, old_password, new_password) # flag表示是否修改成功 | ||||
|     if flag: | ||||
|         session['logged_in'] = False | ||||
|  | @ -134,8 +129,7 @@ window.location.href="/login"; | |||
| 
 | ||||
| ''' | ||||
| 
 | ||||
|         else: | ||||
|             return \ | ||||
| 
 | ||||
| ''' | ||||
| <script> | ||||
| alert('密码修改失败'); | ||||
|  |  | |||
|  | @ -3,8 +3,10 @@ | |||
| # 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 math | ||||
| from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order, sort_in_ascending_order | ||||
|  | @ -52,7 +54,6 @@ def get_difficulty_level(d1, d2): | |||
|     return d | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def revert_dict(d): | ||||
|     ''' | ||||
|     In d, word is the key, and value is a list of dates. | ||||
|  | @ -62,7 +63,8 @@ def revert_dict(d): | |||
|     for k in d: | ||||
|         if type(d[k]) is list:  # d[k] is a list of dates. | ||||
|             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] | ||||
|             lst = freq * ['2021082019']  # why choose this date?  No particular reasons.  I fix the bug in this date. | ||||
| 
 | ||||
|  | @ -79,7 +81,8 @@ 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 | ||||
|     count = 0 | ||||
|     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(), | ||||
|                        reverse=True):  # most recently added words are more important while determining user's level | ||||
|         lst = d_user2[date]  # a list of words | ||||
|         lst2 = []  # a list of tuples, (word, difficulty level) | ||||
|         for word in lst: | ||||
|  | @ -125,17 +128,13 @@ def text_difficulty_level(s, d): | |||
|     return geometric ** (1 / max(count, 1)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
| 
 | ||||
| 
 | ||||
|     d1 = load_record('frequency.p') | ||||
|     # print(d1) | ||||
| 
 | ||||
|     d2 = load_record('words_and_tests.p') | ||||
|     # print(d2) | ||||
| 
 | ||||
| 
 | ||||
|     d3 = get_difficulty_level(d1, d2) | ||||
| 
 | ||||
|     s = ''' | ||||
|  | @ -197,7 +196,6 @@ Amidst the aftermath of this shocking referendum vote, there is great uncertaint | |||
| 
 | ||||
| ''' | ||||
| 
 | ||||
| 
 | ||||
|     s = ''' | ||||
| 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. | ||||
| ''' | ||||
| 
 | ||||
| 
 | ||||
|     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. | ||||
| 
 | ||||
|  | @ -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') | ||||
|     f = open('wordlist.txt',encoding="utf-8") | ||||
|     s = f.read() | ||||
|     f.close() | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
|     print(text_difficulty_level(s, d3)) | ||||
| 
 | ||||
|              | ||||
|  |  | |||
|  | @ -52,7 +52,6 @@ def appears_in_test(word, d): | |||
|     ''' | ||||
|     if not word in d: | ||||
|         return '' | ||||
|     else: | ||||
|     return ','.join(d[word]) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -71,7 +70,7 @@ def mark_word(): | |||
|         d = pickle_idea.merge_frequency(lst, lst_history) | ||||
|         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') | ||||
|         return redirect(url_for('mainpage')) | ||||
|     else: # 不回应GET请求 | ||||
|     # 不回应GET请求 | ||||
|     return 'Under construction' | ||||
| 
 | ||||
| 
 | ||||
|  | @ -92,7 +91,7 @@ def mainpage(): | |||
|         pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p') | ||||
|         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() | ||||
|         number_of_essays = total_number_of_essays() | ||||
|         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) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     ''' | ||||
|     运行程序 | ||||
|  |  | |||
|  | @ -3,9 +3,10 @@ | |||
| # 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 | ||||
| from datetime import datetime | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ def dict2lst(d): | |||
|             for k in d: | ||||
|                 lst.append((k, [datetime.now().strftime('%Y%m%d%H%M')])) | ||||
|             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 [] | ||||
|  |  | |||
|  | @ -11,34 +11,39 @@ function getWord() { | |||
| 
 | ||||
| function fillInWord() { | ||||
|     let word = getWord(); | ||||
|     if (isRead) read(word); | ||||
|     if (!isChoose) return; | ||||
|     if (isRead) {read(word);} | ||||
|     if (!isChoose) {return;} | ||||
|     const element = document.getElementById("selected-words"); | ||||
|     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) { | ||||
|     let msg = new SpeechSynthesisUtterance(str); | ||||
|     msg.rate = rate; | ||||
|     msg.lang = "en-US"; // TODO: add language options menu
 | ||||
|     msg.onboundary = ev => { | ||||
|         if (ev.name == "word") { | ||||
|     msg.onboundary = function(ev) { | ||||
|         if (ev.name === "word") { | ||||
|             current_position = ev.charIndex; | ||||
|         } | ||||
|     } | ||||
|     }; | ||||
|     return msg; | ||||
| } | ||||
| 
 | ||||
| const sliderValue = document.getElementById("rangeValue"); // 显示值
 | ||||
| const inputSlider = document.getElementById("rangeComponent"); // 滑块元素
 | ||||
| inputSlider.oninput = () => { | ||||
| inputSlider.oninput = function(){ | ||||
|     let value = inputSlider.value; // 获取滑块的值
 | ||||
|     sliderValue.textContent = value + '×'; | ||||
|     if (!reader.speaking) return; | ||||
|     sliderValue.textContent = value + "×"; | ||||
|     if (!reader.speaking) {return;} | ||||
|     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; | ||||
|     current_position = 0; | ||||
|     reader.speak(msg); | ||||
|  |  | |||
|  | @ -2,44 +2,60 @@ let isHighlight = true; | |||
| 
 | ||||
| function cancelBtnHandler() { | ||||
|     cancelHighlighting(); | ||||
|     document.getElementById("text-content").removeEventListener("click", fillInWord, 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); | ||||
|     document | ||||
|         .getElementById("text-content") | ||||
|         .removeEventListener("click", fillInWord, 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() { | ||||
|     document.getElementById("text-content").removeEventListener("click", fillInWord2, false); | ||||
|     document.getElementById("text-content").removeEventListener("touchstart", fillInWord2, false); | ||||
|     document.getElementById("text-content").addEventListener("click", fillInWord, false); | ||||
|     document.getElementById("text-content").addEventListener("touchstart", fillInWord, false); | ||||
|     document.getElementById("text-content") | ||||
|         .removeEventListener("click", fillInWord2, false); | ||||
|     document.getElementById("text-content") | ||||
|         .removeEventListener("touchstart", fillInWord2, false); | ||||
|     document.getElementById("text-content") | ||||
|         .addEventListener("click", fillInWord, false); | ||||
|     document.getElementById("text-content") | ||||
|         .addEventListener("touchstart", fillInWord, false); | ||||
|     highLight(); | ||||
| } | ||||
| 
 | ||||
| function getWord() { | ||||
|     return window.getSelection ? window.getSelection() : document.selection.createRange().text; | ||||
|     return (window.getSelection ? | ||||
|             window.getSelection() : | ||||
|             document.selection.createRange().text); | ||||
| } | ||||
| 
 | ||||
| function highLight() { | ||||
|     if (!isHighlight) return; | ||||
|     if (!isHighlight) {return;} | ||||
|     let articleContent = document.getElementById("article").innerText; //将原来的.innerText改为.innerHtml,使用innerText会把原文章中所包含的<br>标签去除,导致处理后的文章内容失去了原来的格式
 | ||||
|     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 allWords = "";  //初始化allWords的值,避免进入判断后编译器认为allWords未初始化的问题
 | ||||
|     if(dictionaryWords != null){//增加一个判断,检查生词本里面是否为空,如果为空,allWords只添加选中的单词
 | ||||
|     if(dictionaryWords !== null){//增加一个判断,检查生词本里面是否为空,如果为空,allWords只添加选中的单词
 | ||||
|         allWords = pickedWords.value + " " + dictionaryWords.value; | ||||
|     } | ||||
|     else{ | ||||
|         allWords = pickedWords.value + " "; | ||||
|     } | ||||
|     const list = allWords.split(" ");//将所有的生词放入一个list中,用于后续处理
 | ||||
|     for (let i = 0; i < list.length; ++i) { | ||||
|         list[i] = list[i].replace(/(^\s*)|(\s*$)/g, ""); //消除单词两边的空字符
 | ||||
|         list[i] = list[i].replace('|', ""); | ||||
|         list[i] = list[i].replace('?', ""); | ||||
|         if (list[i] !== "" && "<mark>".indexOf(list[i]) === -1 && "</mark>".indexOf(list[i]) === -1) { | ||||
|     for (let i = 0; i < list.length; i+=1) { | ||||
|         list[i] = list[i].replace(/(^\s*)|(\s*$)/gm, ""); //消除单词两边的空字符
 | ||||
|         list[i] = list[i].replace("|", ""); | ||||
|         list[i] = list[i].replace("?", ""); | ||||
|         if (list[i] !== "" && | ||||
|             "<mark>".indexOf(list[i]) === -1 && | ||||
|             "</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> "); | ||||
|             articleContent = articleContent.replace( | ||||
|                 new RegExp("\\s"+list[i]+"\\s", "g"), | ||||
|                 " <mark>" + list[i] + "</mark> "); | ||||
|         } | ||||
|     } | ||||
|     document.getElementById("article").innerHTML = articleContent; | ||||
|  | @ -50,21 +66,27 @@ function cancelHighlighting() { | |||
|     let pickedWords = document.getElementById("selected-words"); | ||||
|     const dictionaryWords = document.getElementById("selected-words2"); | ||||
|     const list = pickedWords.value.split(" "); | ||||
|     if (pickedWords != null) { | ||||
|         for (let i = 0; i < list.length; ++i) { | ||||
|             list[i] = list[i].replace(/(^\s*)|(\s*$)/g, ""); | ||||
|     if (pickedWords !== null) { | ||||
|         for (let i = 0; i < list.length; i+=1) { | ||||
|             list[i] = list[i].replace(/(^\s*)|(\s*$)/gm, ""); | ||||
|             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(" "); | ||||
|         for (let i = 0; i < list2.length; ++i) { | ||||
|         for (let i = 0; i < list2.length; i+=1) { | ||||
|             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]里的内容
 | ||||
|                 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 freq = $("#freq_" + theWord).text(); | ||||
|     $.ajax({ | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/familiar", | ||||
|         success:function(response){ | ||||
|             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 (new_freq <= 0) { | ||||
|                     removeWord(theWord); | ||||
|                 } else { | ||||
|                     renderWord({ word: theWord, freq: new_freq }); | ||||
|                     renderWord({ freq: new_freq,word: theWord }); | ||||
|                 } | ||||
|             } else { | ||||
|                 if(new_freq <1) { | ||||
|  | @ -22,7 +22,9 @@ function familiar(theWord) { | |||
|                     $("#freq_" + theWord).text(new_freq); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         }, | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/familiar" | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
|  | @ -31,34 +33,38 @@ function unfamiliar(theWord) { | |||
|     let word = $("#word_" + theWord).text(); | ||||
|     let freq = $("#freq_" + theWord).text(); | ||||
|     $.ajax({ | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/unfamiliar", | ||||
|         success:function(response){ | ||||
|             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) { | ||||
|                 renderWord({ word: theWord, freq: new_freq }); | ||||
|                 renderWord({ freq: new_freq,word: theWord  }); | ||||
|             } else { | ||||
|                 $("#freq_" + theWord).text(new_freq); | ||||
|             } | ||||
|         } | ||||
|         }, | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/unfamiliar" | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function delete_word(theWord) { | ||||
|     let username = $("#username").text(); | ||||
|     let word = theWord.replace('&', '&'); | ||||
|     let word = theWord.replace("&", "&"); | ||||
|     $.ajax({ | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/del", | ||||
|         success:function(response){ | ||||
|             const allow_move = document.getElementById("move_dynamiclly").checked; | ||||
|             const allow_move = document | ||||
|                 .getElementById("move_dynamiclly") | ||||
|                 .checked; | ||||
|             if (allow_move) { | ||||
|                 removeWord(theWord); | ||||
|             } else { | ||||
|                 $("#p_" + theWord).remove(); | ||||
|             } | ||||
|         } | ||||
|         }, | ||||
|         type:"GET", | ||||
|         url:"/" + username + "/" + word + "/del" | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
|  | @ -75,11 +81,12 @@ function delete_word(theWord) { | |||
| function parseWord(element) { | ||||
|     const word = element | ||||
|         .querySelector("a.btn.btn-light[role=button]")  // 获取当前词频元素的词汇元素
 | ||||
|         .innerText  // 获取词汇值;
 | ||||
|     const freq = Number.parseInt(element.querySelector(`#freq_${word}`).innerText);   // 获取词汇的数量
 | ||||
|         .innerText; // 获取词汇值;
 | ||||
|     const freq = Number// 获取词汇的数量
 | ||||
|         .parseInt(element.querySelector(`#freq_${word}`).innerText); | ||||
|     return { | ||||
|         word, | ||||
|         freq | ||||
|         freq, | ||||
|         word | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  | @ -104,7 +111,7 @@ function wordTemplate(word) { | |||
|  */ | ||||
| function removeWord(word) { | ||||
|     // 根据词频信息删除元素
 | ||||
|     word = word.replace('&', '&'); | ||||
|     word = word.replace("&", "&"); | ||||
|     const element_to_remove = document.getElementById(`p_${word}`); | ||||
|     if (element_to_remove != null) { | ||||
|         element_to_remove.remove(); | ||||
|  | @ -134,7 +141,11 @@ function renderWord(word) { | |||
|     // 让发生变化的元素抖动
 | ||||
|     new_element.classList.add("shaking"); | ||||
|     // 移动到该元素
 | ||||
|     new_element.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"}); | ||||
|     new_element.scrollIntoView({ | ||||
|         behavior: "smooth", | ||||
|         block: "center", | ||||
|         inline: "nearest" | ||||
|     }); | ||||
|     // 抖动完毕后删除抖动类
 | ||||
|     setTimeout(() => { | ||||
|         new_element.classList.remove("shaking"); | ||||
|  | @ -145,7 +156,7 @@ function renderWord(word) { | |||
|  * 从string中创建一个HTML元素并返回 | ||||
|  */ | ||||
| function elementFromString(string) { | ||||
|     const d = document.createElement('div'); | ||||
|     const d = document.createElement("div"); | ||||
|     d.innerHTML = string; | ||||
|     return d.children.item(0); | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| """ | ||||
| This module provides methods for user_services | ||||
| """ | ||||
| from datetime import datetime | ||||
| 
 | ||||
| from flask import * | ||||
| 
 | ||||
| # from app import Yaml | ||||
|  | @ -36,6 +38,7 @@ def user_reset(username): | |||
|     else: | ||||
|         return 'Under construction' | ||||
| 
 | ||||
| 
 | ||||
| @userService.route("/<username>/back", methods=['GET']) | ||||
| def user_back(username): | ||||
|     ''' | ||||
|  | @ -48,7 +51,6 @@ def user_back(username): | |||
|         return redirect(url_for('user_bp.userpage', username=username)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @userService.route("/<username>/<word>/unfamiliar", methods=['GET', 'POST']) | ||||
| def unfamiliar(username, word): | ||||
|     ''' | ||||
|  | @ -141,9 +143,6 @@ def userpage(username): | |||
|                                words=words) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @userService.route("/<username>/mark", methods=['GET', 'POST']) | ||||
| def user_mark_word(username): | ||||
|     ''' | ||||
|  |  | |||
|  | @ -2,13 +2,16 @@ | |||
| # Copyright 2019 (C) Hui Lan <hui.lan@cantab.net> | ||||
| # Written permission must be obtained from the author for commercial uses. | ||||
| ########################################################################### | ||||
| 
 | ||||
| """ | ||||
| This Module produces word frequency | ||||
| """ | ||||
| import collections | ||||
| import string | ||||
| import operator | ||||
| import os, sys  # 引入模块sys,因为我要用里面的sys.argv列表中的信息来读取命令行参数。 | ||||
| import pickle_idea | ||||
| 
 | ||||
| 
 | ||||
| def freq(fruit): | ||||
|     ''' | ||||
|     功能: 把字符串转成列表。 目的是得到每个单词的频率。 | ||||
|  | @ -18,7 +21,6 @@ def freq(fruit): | |||
|     ''' | ||||
| 
 | ||||
|     result = [] | ||||
|      | ||||
|     fruit = fruit.lower()  # 字母转小写 | ||||
|     flst = fruit.split()  # 字符串转成list | ||||
|     c = collections.Counter(flst) | ||||
|  | @ -85,10 +87,9 @@ def make_html_page(lst, fname): | |||
|     f.close() | ||||
| 
 | ||||
| 
 | ||||
| ## main(程序入口) | ||||
| # main(程序入口) | ||||
| if __name__ == '__main__': | ||||
|     num = len(sys.argv) | ||||
| 
 | ||||
|     if num == 1:  # 从键盘读入字符串 | ||||
|         s = input() | ||||
|     elif num == 2:  # 从文件读入字符串 | ||||
|  | @ -97,27 +98,19 @@ if __name__ == '__main__': | |||
|     else: | ||||
|         print('I can accept at most 2 arguments.') | ||||
|         sys.exit()  # 结束程序运行, 下面的代码不会被执行了。 | ||||
| 
 | ||||
|     s = remove_punctuation(s)  # 这里是s是实参(argument),里面有值 | ||||
|     L = freq(s) | ||||
|     for x in sort_in_descending_order(L): | ||||
|         print('%s\t%d\t%s' % (x[0], x[1], youdao_link(x[0])))  # 函数导出 | ||||
| 
 | ||||
|     # 把频率的结果放result.html中 | ||||
|     make_html_page(sort_in_descending_order(L), 'result.html') | ||||
| 
 | ||||
|     print('\nHistory:\n') | ||||
|     if os.path.exists('frequency.p'): | ||||
|         d = pickle_idea.load_record('frequency.p') | ||||
|     else: | ||||
|         d = {} | ||||
| 
 | ||||
|     print(sort_in_descending_order(pickle_idea.dict2lst(d))) | ||||
| 
 | ||||
|     # 合并频率 | ||||
|     lst_history = pickle_idea.dict2lst(d) | ||||
|     d = pickle_idea.merge_frequency(L, lst_history) | ||||
|     pickle_idea.save_frequency_to_pickle(d, 'frequency.p') | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue