用Julia语言检查自动图
这个例子演示了一种算法的实现,用于验证自然语言中所谓的autograms—句子的正确性,这些句子包含对其自身结构的准确描述,即描述某些字母,标点符号和其
导言
什么是自动图?
Autogram是描述其自身结构的一种特殊类型的autological(自我描述)句子。 也就是说,这样的句子表示字母表的每个字母,标点符号和其他符号在其中出现多少次。 如果每个提到的项目的计数器与其在同一句子中的实际数量相匹配,则自动图是正确的。
例如,一个自动图可能会说,"这句话中有六个字母'e',"如果它确实包含六个字母'e',那么这是正确描述的一部分。
算法的目的
实现的目的是检查autogram是否正确描述自己,即:
- 对于每个提到的字母或符号:指定的数字与实际数字相同。
- 句子中提到的所有符号确实都被考虑在内。
- 如果需要,是否考虑标点符号。
该算法可用于游戏,语言任务,文本生成,甚至作为人工智能中一种有趣的自我反思方式。
主要部分
连接必要的软件包
# Установка необходимого пакета 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的整数。 如果复合数字由空格分隔(例如,"十一"或"二十五"),则该函数支持复合数字非常重要。
检查自动图的主要功能
"""
    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编程语言中验证autograms正确性的算法的实现。 我们使用了一个外部包 DataStructures 要计算字符的频率,功能已经实现:
-将口头数字转换为数字数字。
-检查每个字符描述的正确性。
-检查句子中所有字符的完整性。
该算法可用于自然语言处理任务,自动验证文本的逻辑正确性,也可以作为编程和语言学领域有趣技巧的一个例子。
该程序已经在几个示例上进行了测试,包括正确和不正确的自动图,这证实了其可操作性。