Автограмма
Проверка автограмм на языке Julia
Этот пример демонстрирует реализацию алгоритма проверки корректности так называемых автограмм — предложений на естественном языке, содержащих точное описание собственной структуры, то есть описывающих число вхождений определённых букв, знаков препинания и других символов.
Введение
Что такое автограмма?
Автограмма — это особый тип автологического (автоописательного) предложения, которое описывает собственную структуру. А именно, в таком предложении указывается, сколько раз в нём встречается каждая буква алфавита, знаки препинания и другие символы. Автограмма корректна, если счётчик каждого упомянутого элемента совпадает с его реальным количеством в этом же предложении.
Например, автограмма может говорить: "В этом предложении шесть букв 'е'", и если в нём действительно содержится шесть букв 'е', то это часть корректного описания.
Цель алгоритма
Цель реализации — проверить, корректно ли автограмма описывает саму себя, то есть:
- Для каждой упомянутой буквы или символа: указанное количество совпадает с реальным.
- Все упомянутые в предложении символы действительно учтены.
- Учитываются ли знаки препинания, если это требуется.
Такой алгоритм может использоваться в играх, лингвистических задачах, генерации текста и даже как интересный способ саморефлексии в искусственном интеллекте.
Основная часть
Подключение необходимых пакетов
# Установка необходимого пакета DataStructures, если он не установлен
import Pkg; Pkg.add("DataStructures")
# Использование пакета DataStructures для удобного подсчёта частоты символов
using DataStructures
Определение словаря чисел в текстовом виде
# Словарь с текстовым представлением чисел от одного до девяносто
const textnumbers = Dict(
"single" => 1, "one" => 1, "two" => 2, "three" => 3, "four" => 4,
"five" => 5, "six" => 6, "seven" => 7, "eight" => 8, "nine" => 9,
"ten" => 10, "eleven" => 11, "twelve" => 12, "thirteen" => 13,
"fourteen" => 14, "fifteen" => 15, "sixteen" => 16,
"seventeen" => 17, "eighteen" => 18, "nineteen" => 19,
"twenty" => 20, "thirty" => 30, "forty" => 40, "fifty" => 50,
"sixty" => 60, "seventy" => 70, "eighty" => 80, "ninety" => 90
)
Этот словарь связывает строковые представления чисел (пример: "five", "twenty-five") с их целочисленными значениями. Используется для преобразования чисел, описанных словами, в конкретные числовые значения.
Функция преобразования текста в число
"""
phrasetointeger(txt)
Преобразование текстовых чисел в числовое значение.
Пример: "twenty five" => 25
"""
function phrasetointeger(txt)
words = split(txt, r"\W+") # Разбивка строки на отдельные слова, исключая знаки препинания
n = 0 # Накопитель числа
for w in words # Проход по всем словам
n += get(textnumbers, w, 0) # Если слово есть в словаре, добавляем его значение
w == "hundred" && (n *= 100) # Если слово сотня — умножаем на 100
end
return n # Возвращаем общее числовое значение
end
Эта функция принимает строку текста, вычленяет из неё числовые слова и составляет из них целое число от 1 до 999. Важно, что функция поддерживает составные числа, если они написаны через пробел (например, "eleven" или "twenty five").
Основная функция проверки автограммы
"""
isautogram(txt, countpunctuation; verbose = true)
Функция проверяет, является ли строка txt корректной автограммой.
Аргументы:
- txt: текст, который нужно проверить
- countpunctuation: считать ли знаки препинания (true/false)
- verbose: выводить ли сообщения об ошибках
"""
function isautogram(txt, countpunctuation; verbose = true)
# Приводим весь текст к строчным буквам
s = lowercase(txt)
# Считаем количество вхождений каждого символа
charcounts = counter(s)
# Словарь символов, о которых нужно проверить упоминание
stillneedmention = Dict(
p[1] => isletter(p[1]) || p[1] != ' ' && countpunctuation ? p[2] : 0
for p in charcounts
)
# Небольшое форматирование строки перед разбором
s = " " * replace(s, r"^\.(?:employs|composed|contains)" => "")
# Разбиваем строку по запятым и двоеточиям — на токены, описывающие символы
for mention in split(s, r"\s*,|:\s*")
mention = replace(mention, r" and$" => "") # Удаляем слово "and" в конце строки
spos = findlast(isspace, mention) # Находим последний пробел — далее будет слово символа
if spos === nothing continue end # Если не нашли — пропускаем
# Извлекаем числовую часть текста (до последнего пробела)
numfromtext = phrasetointeger(mention[begin:spos-1])
numfromtext == 0 && continue # Если число 0 — продолжаем
# Извлекаем часть строки, обозначающую символ
c = mention[begin+spos:end]
if c == "letters"
# Проверка общего количества букв
if numfromtext != count(isletter, txt)
verbose && println("The total letter count (should be $(count(isletter, txt))) is incorrect.")
return false
end
continue
end
# Определяем символ по описанию
ch = contains(c, "comma") ? ',' :
contains(c, "apostrophe") ? '\'' :
contains(c, "hyphen") ? '-' : Char(c[1])
# Проверка количества упомянутого символа
if charcounts[ch] == numfromtext
stillneedmention[ch] = 0 # Помечаем как проверенный
else
verbose && println("The count of $ch in the phrase is incorrect.")
return false
end
end
# Проверяем, не осталось ли символов, упоминание которых забыто
for p in stillneedmention
if p[2] > 0
verbose && println("The letter and count $p was not mentioned in the counts in the phrase.")
return false
end
end
return true # Если всё проверено и совпадает — автограмма корректна
end
Эта основная функция работает по следующим этапам:
- Нормализует текст (все буквы строчные).
- Считает частоту всех символов.
- Обходит все упоминания символов в тексте и проверяет числовые значения.
- Проверяет, все ли реально встречающиеся символы учтены в тексте.
- Возвращает
true
, если всё корректно, иначе —false
.
Если verbose = true
, выводятся поясняющие сообщения об ошибках.
Тестирование автограмм
# Набор тестовых строк — автограмм и не автограмм
for (i, t) in enumerate([
("This sentence employs two a's, two c's, two d's, twenty-eight e's, five f's, three g's, eight h's, eleven i's, three l's, two m's, thirteen n's, nine o's, two p's, five r's, twenty-five s's, twenty-three t's, six v's, ten w's, two x's, five y's, and one z.", false),
("This sentence employs two a's, two c's, two d's, twenty eight e's, five f's, three g's, eight h's, eleven i's, three l's, two m's, thirteen n's, nine o's, two p's, five r's, twenty five s's, twenty three t's, six v's, ten w's, two x's, five y's, and one z.", false),
("This pangram contains four as, one b, two cs, one d, thirty es, six fs, five gs, seven hs, eleven is, one j, one k, two ls, two ms, eighteen ns, fifteen os, two ps, one q, five rs, twenty-seven ss, eighteen ts, two us, seven vs, eight ws, two xs, three ys, & one z.", false),
("This sentence contains one hundred and ninety-seven letters: four a's, one b, three c's, five d's, thirty-four e's, seven f's, one g, six h's, twelve i's, three l's, twenty-six n's, ten o's, ten r's, twenty-nine s's, nineteen t's, six u's, seven v's, four w's, four x's, five y's, and one z.", false),
("Thirteen e's, five f's, two g's, five h's, eight i's, two l's, three n's, six o's, six r's, twenty s's, twelve t's, three u's, four v's, six w's, four x's, two y's.", false),
("Fifteen e's, seven f's, four g's, six h's, eight i's, four n's, five o's, six r's, eighteen s's, eight t's, four u's, three v's, two w's, three x's.", true),
("Sixteen e's, five f's, three g's, six h's, nine i's, five n's, four o's, six r's, eighteen s's, eight t's, three u's, three v's, two w's, four z's.", false),
])
# Проверяем каждую строку
println("Test phrase $i is", isautogram(t[1], t[2]) ? " " : " not ", "a valid autogram.\n")
end
Здесь осуществляется проверка семи примеров текстов, некоторые из которых являются автограммами, а некоторые — нет. Параметр t[2]
указывает, нужно ли учитывать знаки препинания при проверке.
Заключение
Мы рассмотрели реализацию алгоритма проверки корректности автограмм на языке программирования Julia. Мы использовали внешний пакет DataStructures
для подсчёта частоты символов, реализовали функции:
- Преобразования словесных чисел в числовые.
- Проверки корректности описания каждого символа.
- Проверки полноты упоминания всех символов, присутствующих в предложении.
Этот алгоритм может применяться в задачах обработки естественного языка, автоматической проверке логической корректности текстов, а также может служить примером интересных трюков в области программирования и лингвистики.
Программа прошла тестирование на нескольких примерах, включая как корректные, так и некорректные автограммы, что подтверждает её работоспособность.