From fd0969a3eb17b6a0561ba3ab8196390db02f717b Mon Sep 17 00:00:00 2001 From: Albert Tan Date: Thu, 13 Apr 2023 20:36:46 +0800 Subject: 2.0 --- review_it.py | 124 ------------------------------------- review_it_2.0.py | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 124 deletions(-) delete mode 100644 review_it.py create mode 100644 review_it_2.0.py diff --git a/review_it.py b/review_it.py deleted file mode 100644 index 1db5d38..0000000 --- a/review_it.py +++ /dev/null @@ -1,124 +0,0 @@ -''' -Updated: -- Better ways to check syntax -- Let user judge whether answer is correct -- Zero / single / plural in final output - -To be updated: -- Learn answers -- Make orders not matter -- Remove unnecessary spaces or line breaks in input file -- Better ways to handle each line -- Answer judged correct if contains keyword -- Use something better than a dictionary to store incorrect answers -- Title also printed if answer in the section is incorrect -- Consider to use json input file -- Graphic user interface -- Another program to help create related input file -- Optimize -''' - -try: - - import re - import difflib - - - def check_string(line): - return bool(re.match("([-~] [\w\d\s\?\.\"\(\)\[\]\{\}!,;'/]*\Z)|(! version: \d+\.?\d*\s?\Z)|(# [\w\d\s\?\.\"\(\)\[\]\{\}!,;'/]*: [\w\d\s\?\.\"\(\)\[\]\{\}!,;'/]*\Z)", line)) - - - def compare_string(answer, response): - diff = list(difflib.ndiff(answer, response)) - diff_count = 0 - for line in diff: - if line[0] != " ": - diff_count += 1 - return round(1 - (diff_count / len(diff)), 4)*100 - - - file_name = input("Enter file name (with postfix) >> ") - if file_name == "": - file_name = "test_1.2.rvwt" - with open(file_name) as f: - data = f.readlines() - count_prompts = 0 - count_correct = 0 - correct_param = 0.8 - incorrect = [] - - - if len(data) == 0: - raise Exception("Error: file empty") - - if data.pop(0).split(".")[0].replace("\n", "") != "! version: 1": - raise Exception("Error: file version not provided or does not match") - - for line_index in range(len(data)): - if not check_string(data[line_index]): - raise Exception(f"Error: invalid syntax at line {line_index+2} of file '{file_name}'") - - for line_index in range(len(data)): - line = data[line_index] - if line[0] == "-": - line = line[2:].replace("\n", "") - print("\n\n- " + line + " -\n") - if line[0] == "~": - line = line[2:].replace("\n", "") - print("\n" + line + "\n") - elif line[0] == "#": - count_prompts += 1 - line = line[2:].split(":") - prompt = line[0] - answer = line[1][1:-1] - response = input(prompt + ">> ") - if response.lower() == answer.lower(): - print("Correct") - count_correct += 1 - elif compare_string(response.lower(), answer.lower()) >= correct_param: - print(f"Probably correct: answer is '{answer}', similarity {round(compare_string(response.lower(), answer.lower()), 4)}%") - judge = input("Is your answer correct? [y/n] ").lower() - if judge == 'n': - incorrect.append((prompt, answer)) - else: - count_correct += 1 - if judge != "y": - print("Warning: invalid input, answer judged as correct") - else: - print(f"Probably incorrect: answer is '{answer}', similarity {round(compare_string(response.lower(), answer.lower()), 4)}%") - judge = input("Is your answer correct? [y/n] ").lower() - if judge == 'y': - count_correct += 1 - else: - incorrect.append((prompt, answer)) - if judge != "n": - print("Warning: invalid input, answer judged as incorrect") - else: - continue - - if count_prompts <= 1: - print(f"\n\nOut of {count_prompts} question, ", end="") - else: - print(f"\n\nOut of {count_prompts} questions, ", end="") - if count_correct <= 1: - print(f"{count_correct} was answered correctly, ", end="") - else: - print(f"{count_correct} were answered correctly, ", end="") - print(f"which is {round(count_correct / count_prompts, 4)*100}%. ") - - if count_prompts == count_correct: - print("Congratulations for finishing perfectly! ") - else: - if count_prompts - count_correct <= 1: - print(f"The question with incorrect response is listed below: \n") - else: - print(f"The questions with incorrect responses are listed below: \n") - for line in incorrect: - (prompt, answer) = line - print(prompt + "-> " + answer) - - -except Exception as e: - print("\nException: " + str(e)) -except KeyboardInterrupt: - print("\nProcess quitted") diff --git a/review_it_2.0.py b/review_it_2.0.py new file mode 100644 index 0000000..4aee6f0 --- /dev/null +++ b/review_it_2.0.py @@ -0,0 +1,182 @@ +""" +Updated: +- Add line-type 'note' with syntax '=' +- Add line-type 'list' with syntax '&' +- Change syntax of line-type 'title' to '+' instead of '-' +- Remove unnecessary spaces in input file + +To be updated: +- Learn answers +- Remove unnecessary line breaks in input file +- Answer judged correct if contains keyword +- Title and subtitle also printed if answer in the section is incorrect +- Consider to use json input file +- Graphic user interface +- Another program to help create related input file +- Optimize +""" + +try: + + import re + import difflib + + def check_string(line): + string = r"[\w\d\s\?\.\"\(\)\[\]\{\}\-!,;'/]*" + return bool( + re.match( + f"([+~=] {string}\Z)|(! version: \d+\.?\d*\s?\Z)|(# {string}: {string}\Z)|(& ({string}: )+{string}\Z)", + line, + ) + ) + + def compare_string(answer, response): + diff = list(difflib.ndiff(answer, response)) + diff_count = 0 + for line in diff: + if line[0] != " ": + diff_count += 1 + return round(1 - (diff_count / len(diff)), 4) * 100 + + file_name = input("Enter file name (with postfix) >> ") + if file_name == "": + file_name = "test_2.0.rvwt" + with open(file_name) as f: + data = f.readlines() + count_prompts = 0 + count_correct = 0 + correct_param = 70 + incorrect = [] + + if len(data) == 0: + raise Exception("Error: file empty") + + if data.pop(0).split(".")[0].replace("\n", "") != "! version: 2": + raise Exception("Error: file version not provided or does not match") + + for line_index in range(len(data)): + if not check_string(data[line_index]): + raise Exception( + f"Error: invalid syntax at line {line_index+2} of file '{file_name}'" + ) + + for line_index in range(len(data)): + line = data[line_index] + if line[0] == "+": + line = line[2:].replace("\n", "") + print("\n\n- " + line + " -\n") + elif line[0] == "~": + line = line[2:].replace("\n", "") + print("\n" + line + "\n") + elif line[0] == "=": + line = line[2:].replace("\n", "") + print(line) + elif line[0] == "#": + count_prompts += 1 + line = line[2:].split(":") + prompt = line[0] + answer = line[1][1:-1] + if prompt != "": + prompt += " " + response = input(prompt + ">> ") + if response.lower() == answer.lower(): + print("Correct") + count_correct += 1 + elif compare_string(response.lower(), answer.lower()) >= correct_param: + print( + f"Probably correct: answer is '{answer}', similarity {round(compare_string(response.lower(), answer.lower()), 4)}%" + ) + judge = input("Is your answer correct? [[y]/n] ").lower() + if judge == "n": + incorrect.append((prompt, answer)) + else: + count_correct += 1 + if judge != "y": + print("Warning: invalid input, answer judged as correct") + else: + print( + f"Probably incorrect: answer is '{answer}', similarity {round(compare_string(response.lower(), answer.lower()), 4)}%" + ) + judge = input("Is your answer correct? [y/[n]] ").lower() + if judge == "y": + count_correct += 1 + else: + incorrect.append((prompt, answer)) + if judge != "n": + print("Warning: invalid input, answer judged as incorrect") + elif line[0] == "&": + line = line[2:].split(":") + prompt = line.pop(0) + answers = list(map(lambda x: x[1:].lower().replace("\n", ""), line)) + items = len(answers) + count_prompts += items + correct_answers = 1 + answers_max = items + print(prompt) + while answers_max >= correct_answers: + response = input(f"{correct_answers}/{answers_max} >> ") + if response == "": + break + elif response.lower() in answers: + print("Correct") + answers.pop(answers.index(response.lower())) + correct_answers += 1 + else: + max_similarity = 0 + max_index = 0 + for answer in answers: + if compare_string(response.lower(), answer) > max_similarity: + max_similarity = compare_string(response.lower(), answer) + max_index = answers.index(answer) + if max_similarity >= correct_param: + print( + f"Probably correct: closest answer is '{answers[max_index]}', similarity {round(compare_string(response.lower(), answers[max_index]), 4)}%" + ) + judge = input("Is your answer correct? [[y]/n] ").lower() + if judge == "n": + answers_max -= 1 + else: + answers.pop(max_index) + correct_answers += 1 + if judge != "y": + print("Warning: invalid input, answer judged as correct") + else: + print("Probably incorrect") + answers_max -= 1 + if len(answers) != 0: + print("You didn't get the following answers correct: ", end="") + for answer in answers: + incorrect.append((prompt, answer)) + print("'" + answer+ "' ", end="") + count_correct += correct_answers - 1 + if len(answers) != 0: + print() + else: + continue + + if count_prompts <= 1: + print(f"\n\nOut of {count_prompts} question, ", end="") + else: + print(f"\n\nOut of {count_prompts} questions, ", end="") + if count_correct <= 1: + print(f"{count_correct} was answered correctly, ", end="") + else: + print(f"{count_correct} were answered correctly, ", end="") + print(f"which is {round(count_correct / count_prompts * 100, 2)}%. ") + + if count_prompts == count_correct: + print("Congratulations for finishing perfectly! ") + else: + if count_prompts - count_correct <= 1: + print(f"The question with incorrect response is listed below: \n") + else: + print(f"The questions with incorrect responses are listed below: \n") + for line in incorrect: + (prompt, answer) = line + print(prompt + "-> " + answer) + + +except Exception as e: + print("\nException: " + str(e)) +except KeyboardInterrupt: + print("\nProcess quitted") -- cgit v1.2.3