Advertisement
oleh_korkh

Untitled

Jan 3rd, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.71 KB | None | 0 0
  1. import string
  2.  
  3.  
  4. def soundex(word):
  5.     """ Дана функція не реалізовує в повній мірі алгоритм american soundex,
  6.    втім навіть такий спрощений варіант алгоритму цілком підходить для
  7.    нечіткого порівняння. Тут було прийнято правильне рішення спростити
  8.    алгоритм щоб прискорити розробку.
  9.    """
  10.     code = word[0].upper()
  11.     # print(code)
  12.     for x in word[1:]:
  13.         """ Наступна умова не має особливого сенсу, бо якщо інші блоки if
  14.        не знайдуть значимих символів, то цього буде достатньо для ігнорування
  15.        інших.
  16.        """
  17.         if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u' or x == 'y' or x == 'w' or x == 'h' :
  18.             pass
  19.         elif x == 'b' or x == 'f' or x == 'p' or x == 'v':
  20.             """ Хоча з точки зору синтаксису подібний логічний вираз не є
  21.            помилкою, тим не менш, значно зручнішою і звичною для Пітона формою
  22.            запису було б
  23.                if x in 'bfpv'
  24.            """
  25.             code += '1'
  26.         elif x == 'c' or x == 'g' or x == 'j' or x == 'k' or x == 'q' or x == 's' or x == 'x' or x == 'z':
  27.             code += '2'
  28.         elif x == 'd' or x == 't':
  29.             code += '3'
  30.         elif x == 'l':
  31.             code += '4'
  32.         elif x == 'm' or x == 'n':
  33.             code += '5'
  34.         elif x == 'r':
  35.             code += '6'
  36.  
  37.  
  38.     if len(code) > 4:
  39.         """ Якщо нам необхідно вказати зріз від початку, то нуль зазвичай
  40.        не вказують. Тобто, пишуть code[:4]
  41.        """
  42.         code = code[0:4]
  43.     if len(code) < 4:
  44.         """ Замість наступних трьох рядків коду можна написати так:
  45.        code = code.ljust(4, '0')
  46.        Метод ljust розтягує символьний рядок до вказаної кількості
  47.        символів, додаючи праворуч вказаний символ для заповнення.
  48.        """
  49.         difference = 4 - len(code)
  50.         for i in range(difference):
  51.             code += '0'
  52.     return code
  53.  
  54.  
  55.  
  56. def codes(name_of_file):
  57.     """ Сенс даної функції є слабо зрозумілим.
  58.    """
  59.     with open(name_of_file + '.txt', 'r') as f:
  60.         """ Тут ми читаємо слова зі словника words.txt.
  61.        """
  62.         right_words = [x.strip() for x in f.readlines()]
  63.         # print(right_words)
  64.         """ Подальше використання даних мені слабо зрозуміло. Насправді,
  65.        все, що дійсно варто було тут зробити, то це згенерувати набір
  66.        даних у такому вигляді:
  67.        
  68.        {
  69.            'код1': ['слово1', 'слово2'],
  70.            'код2': ['слово3'],
  71.            ...
  72.        }
  73.        
  74.        Згенерувати його можна було б так:
  75.        
  76.        codes_dict = {}
  77.        for x in right_words:
  78.            if x in codes_dict:
  79.                codes_dict[soundex(x)].append(x)
  80.            else:
  81.                codes_dict[soundex(x)] = [x]
  82.                
  83.        Є ще дещо коротша форма запису, але вже з використанням
  84.        дещо модифікованих структур (тип defaultdict), приводжу чисто
  85.        для загального розвитку:
  86.        
  87.        from collections import defaultdict
  88.        codes_dict = defaultdict(list)
  89.        for x in right_words: codes_dict[soundex(x)].append(x)
  90.        
  91.        Саме використання словника, замість списка кортежів наприклад, для
  92.        зберігання кодів і слів, має сенс, бо складність алгоритму
  93.        пошуку ключа для словника є O(1). Тобто, швидкість виборки не залежить
  94.        від кількості елементів у словнику. У той час, як у випадку зі
  95.        списками ми змушені використовувати звичайний лінійний пошук
  96.        з допомогою перебору в циклі for, що в найгіршому випадку
  97.        дає складність O(n), тобто напряму залежить від кількості
  98.        елементів.
  99.        """
  100.         codes_dict = {}
  101.         rw = {}
  102.         codes_list = []
  103.         for i, right_word in enumerate(right_words):
  104.             rw[i] = right_word
  105.             codes_dict[i] = soundex(right_word)
  106.             codes_list += [soundex(right_word)]
  107.         # print(rw)
  108.        
  109.         """ Відповідно, якщо переписати цю функцію з врахуванням вищевказаних
  110.        зауважень, то є сенс щоб вона повертала лише два значення:
  111.        
  112.        return codes_dict, right_words
  113.        """
  114.         return codes_dict, codes_list, rw
  115.  
  116.  
  117. # codes('words')
  118.  
  119. def check():
  120.     codes_dict, codes_list, rw = codes('words')
  121.  
  122.     print(rw)
  123.     with open('input.txt', 'r') as f:
  124.         """ У даному випадку, використовуючи read і об'єднуючи все в один рядок
  125.        ми втрачаємо можливість при виводі вказати номер рядка в якому
  126.        було знайдено помилку. Логічніше було б використовувати читання
  127.        рядками:
  128.        
  129.        rows = [x.strip() for x in f.readlines()]
  130.        """
  131.         words_list = f.read().lower().split(' ')
  132.        
  133.         """ Немає сенсу тут проводити конвертацію у множину, бо
  134.        string.punctuation сам по собі містить лише унікальні символи.
  135.        """
  136.         punctuation = set(string.punctuation)
  137.  
  138.         for i, word in enumerate(words_list):
  139.             """ Видалення символів пунктуації є сенс робити до розбивки рядка
  140.            на слова. В іншому випадку, при наявності в рядку наприклад 20ти
  141.            слів, ми проводитимем операцію 20 разів, хоча могли б лише один раз.
  142.            """
  143.             for x in punctuation:
  144.                 word = word.replace(x,' ')
  145.                
  146.             """ Даний рядок не має сенсу, адже ми вже прочитали файл зі
  147.            словами в середині функції codes. Відповідно, якби ми повернули
  148.            список слів від неї, як я описував вище, то тут ми могли б
  149.            порівнювати з відповідним списком.
  150.            
  151.            Також, нам потрібно реагувати лише не некоректні слова, тому
  152.            логічніше було б писати так:
  153.            
  154.            if word not in right_words:
  155.                print(
  156.                    'Found unknown word:', word,
  157.                    'Suggestions:', ', '.join(codes_dict.get(soundex(word), [])) or 'NONE')
  158.            """
  159.             if word in open('words.txt').read():
  160.                 pass
  161.                 # print("Your word is correct")
  162.             else:
  163.                """ Дана умова не спрацює, якщо слово написано з помилками,
  164.               але у файлі words.txt не знайдеться слова з таким же кодом.
  165.               У випадку з soundex це реальна ситуація, якщо буде помилка
  166.               в першій літері. Така ситуація не звільняє нас від необхідності
  167.               виводу повідомлення про помилку.
  168.               """
  169.                if soundex(word) in codes_list:
  170.                     print('Found unknown word: ' + word + ' Suggestions: ' + rw[i])
  171.  
  172. check()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement