Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import string
- def soundex(word):
- """ Дана функція не реалізовує в повній мірі алгоритм american soundex,
- втім навіть такий спрощений варіант алгоритму цілком підходить для
- нечіткого порівняння. Тут було прийнято правильне рішення спростити
- алгоритм щоб прискорити розробку.
- """
- code = word[0].upper()
- # print(code)
- for x in word[1:]:
- """ Наступна умова не має особливого сенсу, бо якщо інші блоки if
- не знайдуть значимих символів, то цього буде достатньо для ігнорування
- інших.
- """
- if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u' or x == 'y' or x == 'w' or x == 'h' :
- pass
- elif x == 'b' or x == 'f' or x == 'p' or x == 'v':
- """ Хоча з точки зору синтаксису подібний логічний вираз не є
- помилкою, тим не менш, значно зручнішою і звичною для Пітона формою
- запису було б
- if x in 'bfpv'
- """
- code += '1'
- elif x == 'c' or x == 'g' or x == 'j' or x == 'k' or x == 'q' or x == 's' or x == 'x' or x == 'z':
- code += '2'
- elif x == 'd' or x == 't':
- code += '3'
- elif x == 'l':
- code += '4'
- elif x == 'm' or x == 'n':
- code += '5'
- elif x == 'r':
- code += '6'
- if len(code) > 4:
- """ Якщо нам необхідно вказати зріз від початку, то нуль зазвичай
- не вказують. Тобто, пишуть code[:4]
- """
- code = code[0:4]
- if len(code) < 4:
- """ Замість наступних трьох рядків коду можна написати так:
- code = code.ljust(4, '0')
- Метод ljust розтягує символьний рядок до вказаної кількості
- символів, додаючи праворуч вказаний символ для заповнення.
- """
- difference = 4 - len(code)
- for i in range(difference):
- code += '0'
- return code
- def codes(name_of_file):
- """ Сенс даної функції є слабо зрозумілим.
- """
- with open(name_of_file + '.txt', 'r') as f:
- """ Тут ми читаємо слова зі словника words.txt.
- """
- right_words = [x.strip() for x in f.readlines()]
- # print(right_words)
- """ Подальше використання даних мені слабо зрозуміло. Насправді,
- все, що дійсно варто було тут зробити, то це згенерувати набір
- даних у такому вигляді:
- {
- 'код1': ['слово1', 'слово2'],
- 'код2': ['слово3'],
- ...
- }
- Згенерувати його можна було б так:
- codes_dict = {}
- for x in right_words:
- if x in codes_dict:
- codes_dict[soundex(x)].append(x)
- else:
- codes_dict[soundex(x)] = [x]
- Є ще дещо коротша форма запису, але вже з використанням
- дещо модифікованих структур (тип defaultdict), приводжу чисто
- для загального розвитку:
- from collections import defaultdict
- codes_dict = defaultdict(list)
- for x in right_words: codes_dict[soundex(x)].append(x)
- Саме використання словника, замість списка кортежів наприклад, для
- зберігання кодів і слів, має сенс, бо складність алгоритму
- пошуку ключа для словника є O(1). Тобто, швидкість виборки не залежить
- від кількості елементів у словнику. У той час, як у випадку зі
- списками ми змушені використовувати звичайний лінійний пошук
- з допомогою перебору в циклі for, що в найгіршому випадку
- дає складність O(n), тобто напряму залежить від кількості
- елементів.
- """
- codes_dict = {}
- rw = {}
- codes_list = []
- for i, right_word in enumerate(right_words):
- rw[i] = right_word
- codes_dict[i] = soundex(right_word)
- codes_list += [soundex(right_word)]
- # print(rw)
- """ Відповідно, якщо переписати цю функцію з врахуванням вищевказаних
- зауважень, то є сенс щоб вона повертала лише два значення:
- return codes_dict, right_words
- """
- return codes_dict, codes_list, rw
- # codes('words')
- def check():
- codes_dict, codes_list, rw = codes('words')
- print(rw)
- with open('input.txt', 'r') as f:
- """ У даному випадку, використовуючи read і об'єднуючи все в один рядок
- ми втрачаємо можливість при виводі вказати номер рядка в якому
- було знайдено помилку. Логічніше було б використовувати читання
- рядками:
- rows = [x.strip() for x in f.readlines()]
- """
- words_list = f.read().lower().split(' ')
- """ Немає сенсу тут проводити конвертацію у множину, бо
- string.punctuation сам по собі містить лише унікальні символи.
- """
- punctuation = set(string.punctuation)
- for i, word in enumerate(words_list):
- """ Видалення символів пунктуації є сенс робити до розбивки рядка
- на слова. В іншому випадку, при наявності в рядку наприклад 20ти
- слів, ми проводитимем операцію 20 разів, хоча могли б лише один раз.
- """
- for x in punctuation:
- word = word.replace(x,' ')
- """ Даний рядок не має сенсу, адже ми вже прочитали файл зі
- словами в середині функції codes. Відповідно, якби ми повернули
- список слів від неї, як я описував вище, то тут ми могли б
- порівнювати з відповідним списком.
- Також, нам потрібно реагувати лише не некоректні слова, тому
- логічніше було б писати так:
- if word not in right_words:
- print(
- 'Found unknown word:', word,
- 'Suggestions:', ', '.join(codes_dict.get(soundex(word), [])) or 'NONE')
- """
- if word in open('words.txt').read():
- pass
- # print("Your word is correct")
- else:
- """ Дана умова не спрацює, якщо слово написано з помилками,
- але у файлі words.txt не знайдеться слова з таким же кодом.
- У випадку з soundex це реальна ситуація, якщо буде помилка
- в першій літері. Така ситуація не звільняє нас від необхідності
- виводу повідомлення про помилку.
- """
- if soundex(word) in codes_list:
- print('Found unknown word: ' + word + ' Suggestions: ' + rw[i])
- check()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement