Абсолютня: генератор новых слов на Python

Проект, достойный ваших мемов

Абсолютня: генератор новых слов на Python, image #1

Сегодня сделаем простой лингвистический проект: будем собирать новые слова из двух других. Практической ценности здесь мало, но много новых смыслов и неожиданных находок.

Мы подсмотрели идею в Твиттере у Хорошего парня @goodboy_nomore.

В чём идея

Например, у нас есть слово «программа», которое заканчивается на «грамма». И есть слово «грамматика», которое начинается на эти же буквы. Если их записать друг за другом, чтобы слово как бы перетекало одно в другое, получится «программатика». Или вот ещё пара примеров:

абрикосуля = абрикос + косуля (2 буквы в пересечении);

капитание = капитан + питание (5 букв в пересечении).

Смысл понятен: берём первое слово и ищем другое слово, которое начинается на те же буквы, которыми заканчивается первое.

Логика работы

Чтобы не перебирать слова вручную и по памяти, используем силу машин. Как обычно это бывает со словами, мы используем Python — с ним работать со строками проще простого (а слова — это тоже строки).

Алгоритм будет такой:

  1. Берём файл со словарём русского языка и загружаем слова в массив.
  2. Перебираем этот массив двумя вложенными циклами, как в пузырьковой сортировке, чтобы получить очередную пару слов.
  3. Для этой пары слов смотрим, подходит ли конец первого слова к началу второго, а потом наоборот — конец второго слова к началу первого.
  4. Если подходит — выводим найденное сочетание и переходим к новой паре слов.
  5. Если не подходит — пробуем уменьшить количество букв в пересечении и проверяем снова.
  6. Если дошли до минимально допустимого количества букв в пересечении, то делаем вывод, что с этой парой ничего не получится и переходим к следующей.

Ключевой момент алгоритма — минимальное количество букв для пересечения. Оно нужно, чтобы сократить количество найденных вариантов и не генерировать тысячи бесполезных сочетаний типа «миренессанс = мир + ренессанс».

Загружаем файлы из словаря в массив

Нам понадобится словарь слов русского языка в единственном числе и именительном падеже. Таких словарей много, можно взять любой, мы взяли словарь на 68 тысяч слов.

Создаём новый проект на Python и загружаем словарь в массив. Сразу же зададим минимальное количество букв для пересечения:

# открываем файл словаря
with open("singular.txt") as file:
    # и загружаем все слова из него в массив
    text_array = [row.strip() for row in file]

# минимальное количество букв для пересечения
lim = 4

Python

Организуем цикл для перебора слов

Чтобы перебрать попарно все слова, используем простой подход: два вложенных друг в друга цикла. Один будет брать первое слово, второй — следующее, а внутри они будут попарно сравниваться на пересечения.

Сразу сделаем оптимизацию: чтобы не писать два раза один и тот же код для проверки разного порядка слов, мы вынесем это в функцию, а в цикле сошлёмся на неё. Саму функцию напишем на следующем шаге, а пока вот циклы:

# перебираем все слова с первого до предпоследнего
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

Функция для склеивания слов

У нас есть минимальное количество букв для склеивания, но нет максимального. Чтобы у нас была точка отсчёта, стартовое количество букв посчитаем так:

  1. Найдём длину первого слова.
  2. Затем длину второго слова.
  3. Возьмём наименьшее из них
  4. Вычтем из результата единицу, чтобы у нас не было ситуации, когда одно слово полностью вошло в другое — автодорога = автодорога + дорога. Эта недостающая буква и будет страховкой.

Для выделения части слова используем квадратные скобки с двоеточием — в Питоне они нарезают строку на части. Работает это так:

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 -= 1



Python
Каждый найденный результат программа сразу выводит на экран
Каждый найденный результат программа сразу выводит на экран

Готовый код

# открываем файл словаря
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/

Что дальше

Ради интереса можно написать код, который так будет генерировать новое слово из цепочки нескольких слов любой длины. Пока это отложим, но если вам хочется прямо сейчас — берите наш код и отталкивайтесь от него, правок для нового проекта будет не очень много.

911 views·23 shares