Абсолютня: генератор новых слов на Python
Проект, достойный ваших мемов
Сегодня сделаем простой лингвистический проект: будем собирать новые слова из двух других. Практической ценности здесь мало, но много новых смыслов и неожиданных находок.
Мы подсмотрели идею в Твиттере у Хорошего парня @goodboy_nomore.
В чём идея
Например, у нас есть слово «программа», которое заканчивается на «грамма». И есть слово «грамматика», которое начинается на эти же буквы. Если их записать друг за другом, чтобы слово как бы перетекало одно в другое, получится «программатика». Или вот ещё пара примеров:
абрикосуля = абрикос + косуля (2 буквы в пересечении);
капитание = капитан + питание (5 букв в пересечении).
Смысл понятен: берём первое слово и ищем другое слово, которое начинается на те же буквы, которыми заканчивается первое.
Логика работы
Чтобы не перебирать слова вручную и по памяти, используем силу машин. Как обычно это бывает со словами, мы используем Python — с ним работать со строками проще простого (а слова — это тоже строки).
Алгоритм будет такой:
- Берём файл со словарём русского языка и загружаем слова в массив.
- Перебираем этот массив двумя вложенными циклами, как в пузырьковой сортировке, чтобы получить очередную пару слов.
- Для этой пары слов смотрим, подходит ли конец первого слова к началу второго, а потом наоборот — конец второго слова к началу первого.
- Если подходит — выводим найденное сочетание и переходим к новой паре слов.
- Если не подходит — пробуем уменьшить количество букв в пересечении и проверяем снова.
- Если дошли до минимально допустимого количества букв в пересечении, то делаем вывод, что с этой парой ничего не получится и переходим к следующей.
Ключевой момент алгоритма — минимальное количество букв для пересечения. Оно нужно, чтобы сократить количество найденных вариантов и не генерировать тысячи бесполезных сочетаний типа «миренессанс = мир + ренессанс».
Загружаем файлы из словаря в массив
Нам понадобится словарь слов русского языка в единственном числе и именительном падеже. Таких словарей много, можно взять любой, мы взяли словарь на 68 тысяч слов.
Создаём новый проект на Python и загружаем словарь в массив. Сразу же зададим минимальное количество букв для пересечения:
# открываем файл словаря
with open("singular.txt") as file:
# и загружаем все слова из него в массив
text_array = [row.strip() for row in file]
# минимальное количество букв для пересечения
lim = 4Python
Организуем цикл для перебора слов
Чтобы перебрать попарно все слова, используем простой подход: два вложенных друг в друга цикла. Один будет брать первое слово, второй — следующее, а внутри они будут попарно сравниваться на пересечения.
Сразу сделаем оптимизацию: чтобы не писать два раза один и тот же код для проверки разного порядка слов, мы вынесем это в функцию, а в цикле сошлёмся на неё. Саму функцию напишем на следующем шаге, а пока вот циклы:
# перебираем все слова с первого до предпоследнего
for i in range (0,len(text_array)-1):
# и сразу перебираем все слова от следующего до последнего
for j in range (i+1,len(text_array)):
# пробуем найти пересечение первого слова со вторым
glue(text_array[i], text_array[j])
# а потом второго — с первым
glue(text_array[j], text_array[i])Python
Функция для склеивания слов
У нас есть минимальное количество букв для склеивания, но нет максимального. Чтобы у нас была точка отсчёта, стартовое количество букв посчитаем так:
- Найдём длину первого слова.
- Затем длину второго слова.
- Возьмём наименьшее из них
- Вычтем из результата единицу, чтобы у нас не было ситуации, когда одно слово полностью вошло в другое — автодорога = автодорога + дорога. Эта недостающая буква и будет страховкой.
Для выделения части слова используем квадратные скобки с двоеточием — в Питоне они нарезают строку на части. Работает это так:
S[0:2] — вернёт первые три символа из строки («Привет» → «При»);
S[3:5] — вернёт с третьего по пятый символ («Привет» → «иве»);
S[:3] — вернёт первые четыре символа из строки, потому что раз нет первого аргумента, то считаем от начала («Привет» → «Прив»);
S[3:] — вернёт все символы из строки, начиная с четвёртого, так как нумерация идёт с нуля, а конец в диапазоне не указан («Привет» → «вет»)
Ещё можно использовать отрицательные значения — в этом случае Python будет считать с конца строки:
S[-2:] — вернёт последние три символа из строки («Привет» → «вет»)
S[:-2] — вернёт всё от начала строки и до минус второго символа («Привет» → «При»)
Зная это, мы теперь легко можем написать функцию, которая проверяет и склеивает слова. Заодно добавим проверку на слово из словаря: если то, что у нас получилось, уже и так было в словаре, значит, мы ничего нового не придумали и выводить это не надо.
# функция, которая склеивает слова
def glue(x,y):
# находим максимальное доступное количество букв пересечения для этих двух слов
start = min(len(x),len(y))-1
# пока это количество больше минимального
while start >= lim:
# берём конец первого слова
s1 = x[-start:]
# берём начало второго слова
s2 = y[:start]
# если они равны
if s1 == s2:
# склеиваем эти слова
s = x + y[start:]
# если получившегося слова нет в изначальном словаре
if s not in text_array:
# то выводим его и то, из чего оно получилось
print(s + " = " + x + " + " + y)
# как только нашли пересечение слов — выходим из цикла
break
# если с текущим количеством букв пересечение не получается
else:
# уменьшаем количество букв для пересечения
start -= 1Python
Готовый код
# открываем файл словаря
with open("singular.txt") as file:
# и загружаем все слова из него в массив
text_array = [row.strip() for row in file]
# минимальное количество букв для пересечения
lim = 4
# функция, которая склеивает слова
def glue(x,y):
# находим максимальное доступное количество букв пересечения для этих двух слов
start = min(len(x),len(y))-1
# пока это количество больше минимального
while start >= lim:
# берём конец первого слова
s1 = x[-start:]
# берём начало второго слова
s2 = y[:start]
# если они равны
if s1 == s2:
# склеиваем эти слова
s = x + y[start:]
# если получившегося слова нет в изначальном словаре
if s not in text_array:
# то выводим его и то, из чего оно получилось
print(s + " = " + x + " + " + y)
# как только нашли пересечение слов — выходим из цикла
break
# если с текущим количеством букв пересечение не получается
else:
# уменьшаем количество букв для пересечения
start -= 1
# перебираем все слова с первого до предпоследнего
for i in range (0,len(text_array)-1):
# и сразу перебираем все слова от следующего до последнего
for j in range (i+1,len(text_array)):
# пробуем найти пересечение первого слова со вторым
glue(text_array[i], text_array[j])
# а потом второго — с первым
glue(text_array[j], text_array[i])Python
500 результатов
Смотрите по ссылке: https://thecode.media/g1glukozanostra/
Что дальше
Ради интереса можно написать код, который так будет генерировать новое слово из цепочки нескольких слов любой длины. Пока это отложим, но если вам хочется прямо сейчас — берите наш код и отталкивайтесь от него, правок для нового проекта будет не очень много.
