HSE DH 2022 — 2024
«ГОЛОСА ПЛАТОНА»
Ольга Валерьевна Алиева
Борис Валерьевич Орехов
Варвара Крючкова
Дмитрий Воинов
Коротко о главном
Исследователи сочинений Платона как правило используют количественные методы для анализа вопросов авторства и хронологии произведений.

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

Наделяет ли Платон своих персонажей индивидуальным стилем?

Происходит ли это как в ранних, так и в поздних диалогах?

Сократ из ранних произведений и из поздних диалогов — это один и тот же персонаж с точки зрения стилометрического анализа?

Команда проекта
  • Борис Валерьевич
    Орехов
    Ведущий научный сотрудник:Международной лаборатории языковой конвергенции

    Доцент:Факультет гуманитарных наук / Школа лингвистики НИУ ВШЭ

    Руководитель образовательной программы:Цифровые методы в гуманитарных науках (ЦМГН) НИУ ВШЭ

    Кандидат филологических наук
  • Ольга Валерьевна
    Алиева
    Доцент факультета
    гуманитарных наук

    Доцент Школы философии и культурологии НИУ ВШЭ

    Кандидат филологических наук
  • Дмитрий
    Воинов
    Студент НИУ ВШЭ / ЦМГН 22-24
  • Варвара
    Крючкова
    Студент НИУ ВШЭ / ЦМГН 22-24
МЕТОДЫ

Общенаучные методы: аналитический, компаративный, дескриптивный.

Методы DH: стилометрия
Как «услышать» голоса:
логика действий
Определить список диалогов для разметки
Все диалоги с «пересказанной речью»
Завершить разметку «пересказанных диалогов»
Добавить теги <said who="name"><label>name</label> + </said>
Извлечь все реплики из древнегреческой версии текста
Например, все реплики Сократа из различных произведений
Сформировать набор корпусов с репликами персонажей
Например, 10 персонажей «Федона» и т.п.
Провести стилометрическое исследование
Речи героев анализируются с помощью Stylo
Сделать выводы
Ответить на исследовательские вопросы, упомянутые выше
Stephanus
Для переноса XML-разметки в древнегреческую версию нам потребуются:

Библиотеки:
BeautifulSoup — для извлечения данных из файлов HTML и XML);

Модуль:
re — для работы с регулярными выражениями: поисака и сопоставления строк;

Первый этап — парсинг XML-файла с помощью библиотеки BeautifulSoup.

1
Начало работы

!wget https://raw.githubusercontent.com/PerseusDL/canonical-greekLit/master/data/tlg0059/tlg011/tlg0059.tlg011.perseus-eng2.xml
!wget https://raw.githubusercontent.com/PerseusDL/canonical-greekLit/master/data/tlg0059/tlg011/tlg0059.tlg011.perseus-grc2.xml

from bs4 import BeautifulSoup

with open("tlg0059.tlg011.perseus-eng2.xml") as fp: 
  soup = BeautifulSoup(fp, 'lxml')

all_divs = soup.find_all('div', {"subtype" : "section"})
for div in all_divs:
  print(div['n'])
Загружаем английскую и древнегреческую версию «Пира» в XML с GitHub с помощью команды "wget".

Используем BeautifulSoup для парсинга английского XML-файла и создания объекта BeautifulSoup с именем "soup" и далее работаем с ним.

Используем метод "find_all" для поиска всех тегов "div" с атрибутом "subtype", установленным на "section".

Для каждой секции код извлекает значение атрибута "n", который представляет номер секции, используя синтаксис "div['n']".

2

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 2:
    who1 = said[0]['who']
    who2 = said[1]['who']
    print(n, who1, who2)
180 #Phaedrus #Pausanias 189 #Aristophanes #Aristophanes 197 #Agathon #Agathon
Переменная "all_divs" получает список всех тегов "div" с атрибутом "subtype", установленным на "section", используя метод "find_all" объекта "soup".

Затем используется цикл "for" для перебора каждого элемента списка "all_divs". Для каждого элемента переменная "n" получает значение атрибута "n", который представляет номер секции.

Далее, метод "find_all" используется для поиска всех тегов "said" внутри текущего элемента "div" с атрибутом "direct", установленным на "false". Эти теги представляют реплики в диалоге.

Если количество таких тегов равно двум, то переменные "who1" и "who2" получают значения атрибутов "who" первой и второй реплик соответственно.

3
Страницы, где встречается 1 тэг <said>,
т.е. одна реплика («моностраница»)


all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    print(n, who)
178 #Phaedrus 179 #Phaedrus 181 #Pausanias 182 #Pausanias 183 #Pausanias 184 #Pausanias 185 #Pausanias 186 #Eryximachus 187 #Eryximachus 188 #Eryximachus 190 #Aristophanes 191 #Aristophanes 192 #Aristophanes 193 #Aristophanes 195 #Agathon 196 #Agathon 201 #Socrates 202 #Socrates 203 #Socrates 204 #Socrates 205 #Socrates 206 #Socrates 207 #Socrates 208 #Socrates 209 #Socrates 210 #Socrates 211 #Socrates 212 #Socrates 215 #Alcibiades 216 #Alcibiades 217 #Alcibiades 218 #Alcibiades 219 #Alcibiades 220 #Alcibiades 221 #Alcibiades 222 #Alcibiades
Переменная "all_divs" получает список всех тегов "div" с атрибутом "subtype", установленным на "section", используя метод "find_all" объекта "soup".

Затем используется цикл "for" для перебора каждого элемента списка "all_divs". Для каждого элемента переменная "n" получает значение атрибута "n", который представляет номер секции.

Далее, метод "find_all" используется для поиска всех тегов "said" внутри текущего элемента "div" с атрибутом "direct", установленным на "false". Эти теги представляют реплики в диалоге.

Если количество таких тегов равно одному, то переменная "who" получает значение атрибута "who" реплики.

4
Кто и на каких страницах говорит.
Выведены только те страницы, на которых встречается 1 <said> (т.е. присутствует 1 спикер)


all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    text = div.find_all(text = True)
    print(n, who)
    print(text)
Переменная "all_divs" получает список всех тегов "div" с атрибутом "subtype", установленным на "section", используя метод "find_all" объекта "soup".

Затем используется цикл "for" для перебора каждого элемента списка "all_divs". Для каждого элемента переменная "n" получает значение атрибута "n", который представляет номер секции.

Далее, метод "find_all" используется для поиска всех тегов "said" внутри текущего элемента "div" с атрибутом "direct", установленным на "false". Эти теги представляют реплики в диалоге.

Если количество таких тегов равно одному, то переменная "who" получает значение атрибута "who" реплики.

Метод "find_all" также используется для поиска всех текстовых элементов внутри текущего элемента "div". Эти элементы представляют текст, следующий после реплики.

5
2-я строчка: текст страницы целиком;
3-я строчка: текст внутри said


all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    text_div = div.find_all(text = True)
    said = said[0]
    text_said = said.find_all(text = True)
    print(n, who)
    print(text_div)
    print(text_said)
    print()
Переменная "all_divs" получает список всех тегов "div" с атрибутом "subtype", установленным на "section", используя метод "find_all" объекта "soup".

Затем используется цикл "for" для перебора каждого элемента списка "all_divs". Для каждого элемента переменная "n" получает значение атрибута "n", который представляет номер секции.

Далее, метод "find_all" используется для поиска всех тегов "said" внутри текущего элемента "div" с атрибутом "direct", установленным на "false". Эти теги представляют реплики в диалоге.

Если количество таких тегов равно одному, то переменная "who" получает значение атрибута "who" реплики.

Метод "find_all" также используется для поиска всех текстовых элементов внутри текущего элемента "div". Эти элементы представляют текст, следующий после реплики.

Затем метод "find_all" используется для поиска всех текстовых элементов внутри тега "said". Эти элементы представляют текст реплики.

Цель этого кода— извлечение имен говорящих, текста после их реплик и текста реплик в диалоге из XML-файла, если каждая секция содержит ровно одну реплику.

6
Создали два списка, вывели первый их элемент.
Далее удаляем '\n'


texts_div = []
texts_said = []

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    text_div = div.find_all(text = True)
    texts_div.append(text_div)
    said = said[0]
    text_said = said.find_all(text = True)
    texts_said.append(text_said)

print(texts_div[0])
print(texts_said[0])
В этом коде мы создаем два пустых списка для хранения текстового содержимого каждого элемента div и said соответственно.

Затем мы используем метод find_all() для поиска всех элементов div с атрибутом subtype, установленным в "section". Мы перебираем эти элементы и для каждого div проверяем, содержит ли он ровно один элемент said с атрибутом direct, установленным в "false". Если да, мы извлекаем текстовое содержимое div и said и добавляем их в соответствующие списки.

В конце кода мы выводим текстовое содержимое первого элемента из каждого списка для демонстрации того, как хранятся текстовые данные в списках.

7
Импортировали библиотеку re, удалили '\n' (result1),
а также '\n' с пробелами (result2)


import re

my_str = str(texts_div[0])
result1 = re.sub(r"'\\n', ", "", my_str)
result2 = re.sub(r"'\\n\s+", "", result1)
print(my_str)
print(type(my_str))
print(result1)
print(result2)
В этом коде мы используем модуль re для поиска и замены подстрок в текстовой строке.

Мы начинаем с того, что преобразуем список texts_div[0] в текстовую строку с помощью функции str(). Затем мы применяем метод sub() модуля re для замены подстрок, удовлетворяющих заданному регулярному выражению, на пустую строку. Регулярное выражение r"'\\n', " ищет все вхождения подстроки '\n', в тексте, которые могут встречаться после каждой строки в списке. Заменяем такие вхождения на пустую строку.

Затем мы применяем еще одно регулярное выражение r"'\\n\s+", которое ищет все вхождения подстроки '\n в тексте, которые могут встречаться в начале строки в списке. Заменяем такие вхождения на пустую строку.

В конце кода мы выводим исходную текстовую строку, ее тип, а также две результирующие строки с примененными заменами.

8

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    text_div = re.sub(r"'\\n\s+|'\\n', ", "", str(div.find_all(text = True)))
    said = said[0]
    text_said = re.sub(r"'\\n\s+|'\\n', ", "", str(said.find_all(text = True)))

    print(n, text_div == text_said)
178 False 179 True 181 True 182 True 183 True 184 True 185 False 186 False 187 True 188 True 190 True 191 True 192 True 193 False 195 False 196 True 201 False 202 True 203 True 204 True 205 True 206 True 207 True 208 True 209 True 210 True 211 True 212 False 215 False 216 True 217 True 218 True 219 True 220 True 221 True 222 False
В этом коде мы перебираем все элементы div с атрибутом subtype, равным "section". Затем мы находим все элементы said с атрибутом direct, равным "false", внутри каждого элемента div. Если есть только один элемент said, мы извлекаем значение его атрибута who и текст внутри элемента div и элемента said.

Чтобы сравнить текст внутри элемента div и элемента said, мы используем регулярные выражения для удаления любых переводов строк и лишних пробелов из строк с помощью функции re.sub(). Затем мы печатаем номер раздела, а также True, если текст внутри элемента div и элемента said идентичен, и False в противном случае.

9

with open("tlg0059.tlg011.perseus-grc2.xml") as fp: 
  greek_soup = BeautifulSoup(fp, 'lxml')

f = open('divs.xml', 'w')
all_divs = greek_soup.find_all('div', {"subtype" : "section"})
for div in all_divs:
  n = div['n']
  str_div = str(div)
  if n in mono:
    str_div = str_div.replace('</said>', '</said></said>')
    str_div = str_div.replace('<said rend="merge" who="#Ἀπολλόδωρος">', '<said who="#Ἀπολλόδωρος" rend="merge"><said who="{}" direct="false">'.format(mono[n]))
  f.write(str_div)
f.close()
Код читает файл tlg0059.tlg011.perseus-grc2.xml и создает объект greek_soup типа BeautifulSoup, представляющий структуру и содержание XML-файла в виде дерева элементов. Затем код выполняет действия с использованием этого объекта.

Затем мы открываем файл 'divs.xml' для записи, затем находит все элементы 'div' с атрибутом 'subtype' равным 'section' в объекте BeautifulSoup для греческого текста. Затем он проходит циклом по всем найденным элементам 'div' и находит значение атрибута 'n'. Далее он преобразует текущий элемент 'div' в строку и сохраняет его в переменную 'str_div'. Если значение 'n' находится в словаре 'mono', то он заменяет '</said>' на '</said></said>' и заменяет '<said rend="merge" who="#Ἀπολλόδωρος">' на '<said who="#Ἀπολλόδωρος" rend="merge"><said who="{}" direct="false">'.format(mono[n]). Затем строка 'str_div' записывается в файл 'divs.xml'. Когда цикл заканчивается, файл закрывается.

10
Ищем страницы, где реплика
заканчивается посередине


all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
  n = div['n']
  said = div.find_all('said', {"direct": "false"})
  if len(said) == 1:
    who = said[0]['who']
    text_div = re.sub(r"'\\n\s+|'\\n', ", "", str(div.find_all(text = True)))
    said = said[0]
    text_said = re.sub(r"'\\n\s+|'\\n', ", "", str(said.find_all(text = True)))
    if text_div != text_said:
      str_div = str(div)
      str_div = re.sub(r">[\\n \\t\\r\\s]+<", "><", str_div, re.MULTILINE)
      print(str_div)
      print()
Этот код ищет все блоки div с атрибутом subtype равным section и проверяет, содержат ли они ровно один элемент said с атрибутом direct равным false. Затем он сравнивает текст внутри блока div с текстом внутри said. Если они не совпадают, он выводит блок div вместе с его содержимым в качестве строки и печатает его.
Также он заменяет некоторые символы, такие как пробелы, новые строки и табуляцию, используя регулярное выражение re.sub(). Это делается для того, чтобы убедиться, что текст в блоке div и said действительно различается, даже если есть некоторые различия в форматировании.

11

import re

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
    n = div['n']
    said = div.find_all('said', {"direct": "false"})
    if len(said) == 1:
        who = said[0]['who']
        text_div = re.sub(r"'\\n\s+|'\\n', ", "", str(div.find_all(text=True)))
        said = said[0]
        text_said = re.sub(r"'\\n\s+|'\\n', ", "", str(said.find_all(text=True)))
        if text_div != text_said:
            str_div = str(div)
            str_div = str_div.replace("\n", "")
            str_div = re.sub(r">[\\n \\t\\r\\s]+<", "><", str_div, flags=re.MULTILINE)
            print(str_div)
            print()
Код в целом аналогичен предыдущему, за исключением того, что здесь добавлен импорт модуля re и использование его для замены символов переноса строк и пробелов внутри тегов на пустые строки. Также использован параметр flags=re.MULTILINE, чтобы обработать многострочный текст.

12
Находим said who с Апполодором, затем идет said who, затем заменяем первый тег

speaker = {}

import re

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
    n = div['n']
    said = div.find_all('said', {"direct": "false"})
    if len(said) == 1:
        who = said[0]['who']
        text_div = re.sub(r"'\\n\s+|'\\n', ", "", str(div.find_all(text=True)))
        said = said[0]
        text_said = re.sub(r"'\\n\s+|'\\n', ", "", str(said.find_all(text=True)))
        if text_div != text_said:
            str_div = str(div)
            str_div = str_div.replace("\n", "")
            str_div = re.sub(r">[\\n \\t\\r\\s]+<", "><", str_div, flags=re.MULTILINE)
            print(n, who)
            print()
178 #Phaedrus 185 #Pausanias 186 #Eryximachus 193 #Aristophanes 195 #Agathon 201 #Socrates 212 #Socrates 215 #Alcibiades 222 #Alcibiades
Код выше проходит через все блоки <div>, имеющие атрибут "subtype" со значением "section". Затем он проверяет, имеется ли ровно один элемент <said>, имеющий атрибут "direct" со значением "false". Если это так, код извлекает значение атрибута "who" этого элемента и сохраняет его в переменную "who". Затем код удаляет все переводы строк из текста элемента <div> и преобразует его в строку. Кроме того, он делает то же самое с текстом элемента <said> и сохраняет его в переменную "text_said". Затем, если значения "text_div" и "text_said" не совпадают, код заменяет все переводы строк, пробелы и табуляции между тегами на единственный пробел. Наконец, он выводит номер блока <div> и значение атрибута "who" элемента <said>, если "text_div" и "text_said" не совпадают.

13
Добавили номера страниц и имена говорящих в словарь speaker и вставляем нужные теги в греческий текст

speaker = {}

import re

all_divs = soup.find_all('div', {"subtype": "section"})
for div in all_divs:
    n = div['n']
    said = div.find_all('said', {"direct": "false"})
    if len(said) == 1:
        who = said[0]['who']
        text_div = re.sub(r"'\\n\s+|'\\n', ", "", str(div.find_all(text=True)))
        said = said[0]
        text_said = re.sub(r"'\\n\s+|'\\n', ", "", str(said.find_all(text=True)))
        if text_div != text_said:
            str_div = str(div)
            str_div = str_div.replace("\n", "")
            str_div = re.sub(r">[\\n \\t\\r\\s]+<", "><", str_div, flags=re.MULTILINE)
            if '<said rend="merge" who="#Apollodorus"><said' in str_div:
              speaker[n] = who
              list_milestones = re.findall('(</said>)?<milestone ed="P"', str_div)
              print(list_milestones)
              print(n)
              print(list_milestones.index('</said>'))
              print()
В данном коде создается словарь speaker, который в дальнейшем будет содержать информацию о том, кто произносит речь в каждой секции текста.

Затем в цикле происходит поиск всех секций текста с помощью метода find_all() из библиотеки BeautifulSoup. Далее для каждой секции проверяется, содержит ли она только одно высказывание. Если это так, то получается информация о том, кто произносит высказывание и какой текст содержится в данной секции. Если текст в секции не соответствует тексту высказывания, то создается строка str_div, которая содержит теги XML-разметки данной секции, но без лишних пробелов и символов переноса строк.

Далее в коде проверяется, содержится ли в str_div тег <said> с атрибутом rend="merge" who="#Apollodorus"><said. Если это так, то для данной секции записывается информация о том, кто произносит речь, используя словарь speaker, а также получается список list_milestones, содержащий все теги <milestone ed="P"> в данной секции, и находится индекс последнего тега </said> в данном списке.

14

f = open('divs2.xml', 'w')
all_divs = greek_soup.find_all('div', {"subtype" : "section"})
for div in all_divs:
  n = div['n']
  str_div = str(div)
  if n in speaker:
    #str_div = str_div.replace('</said>', '</said></said>')
    str_div = str_div.replace('<said rend="merge" who="#Ἀπολλόδωρος">', '<said who="#Ἀπολλόδωρος" rend="merge"><said who="{}" direct="false">'.format(speaker[n]))
  f.write(str_div)
f.close() 
Код создает новый файл 'divs2.xml' и записывает в него все секции документа greek_soup с заменой реплик Ἀπολλόδωρος на who для соответствующей секции, как было определено в словаре speaker. Получившийся файл divs2.xml будет иметь такую же структуру и содержание, как и исходный файл divs.xml, но с изменениями в репликах говорящих.
Что удалось сделать
- сопоставили спикера и страницы

- проверили, корректно ли сформирована excel таблица (true = 1 спикер на страницу с атрибутом said в начале и в конце; false = 2 спикера)

- расставили атрибуты так, чтобы машина считывала реплику (перенос в версию диалога на древнегреческом языке из английской версии)

- недостающие атрибуты переносятся в греческий диалог из английской версии

15
Итоговый код к настоящему моменту

#Импортирование необходимых библиотек
import os
import re
from bs4 import BeautifulSoup

#Загрузка и сохранение XML-файлов
!wget https://raw.githubusercontent.com/PerseusDL/canonical-greekLit/master/data/tlg0059/tlg011/tlg0059.tlg011.perseus-eng2.xml
!wget https://raw.githubusercontent.com/PerseusDL/canonical-greekLit/master/data/tlg0059/tlg011/tlg0059.tlg011.perseus-grc2.xml

#Загрузка XML-файлов
with open('tlg0059.tlg011.perseus-eng2.xml', 'r') as file:
data_eng = file.read()

with open('tlg0059.tlg011.perseus-grc2.xml', 'r') as file:
data_greek = file.read()

#Парсинг XML-файлов с помощью BeautifulSoup
eng_soup = BeautifulSoup(data_eng, 'xml')
greek_soup = BeautifulSoup(data_greek, 'xml')

#Создаём словарь для хранения информации о говорящем
speaker = {}

#Находим все div-элементы с подтипом "section" в греческом XML
all_divs = greek_soup.find_all('div', {"subtype": "section"})

#Пройдём по каждому div-элементу и извлечём информацию о говорящем
for div in all_divs:
n = div['n']
said = div.find_all('said', {"direct": "false"})
if len(said) == 1:
who = said[0]['who']
text_div = re.sub(r"'\n\s+|'\n', ", "", str(div.find_all(text=True)))
said = said[0]
text_said = re.sub(r"'\n\s+|'\n', ", "", str(said.find_all(text=True)))
if text_div != text_said:
str_div = str(div)
str_div = str_div.replace("\n", "")
str_div = re.sub(r">[\n \t\r\s]+<", "><", str_div, flags=re.MULTILINE)
if '<said rend="merge" who="#Apollodorus"><said' in str_div:
speaker[n] = who
list_milestones = re.findall('(</said>)?<milestone ed="P"', str_div)
print(list_milestones)
print(n)
print(list_milestones.index('</said>'))
print()

#Откроем новый файл для записи измененного XML на древнегреческом
with open('divs2.xml', 'w') as file:
all_divs = greek_soup.find_all('div', {"subtype" : "section"})
for div in all_divs:
n = div['n']
str_div = str(div)
if n in speaker:
str_div = str_div.replace('<said rend="merge" who="#Ἀπολλόδωρος">', '<said who="#Ἀπολλόδωρος" rend="merge"><said who="{}" direct="false">'.format(speaker[n]))
file.write(str_div)

#Выводим сообщение о том, что файл был записан
print('success')

16
Разметка вручную

from bs4 import BeautifulSoup

# Load the XML file
with open("symposium_ed.xml", "r") as file:
    xml_data = file.read()

# Parse the XML
soup = BeautifulSoup(xml_data, "xml")

# Find all <said> tags
said_tags = soup.find_all("said")

# Extract quotes and names
for said_tag in said_tags:
    name = said_tag["who"]
    quote = said_tag.get_text(strip=True)
    print(f"{name}:")
    print(quote)
#Σωκράτης:

ἐπὶ δεῖπνον εἰς Ἀγάθωνος. χθὲς γὰρ αὐτὸν διέφυγον τοῖς ἐπινικίοις, φοβηθεὶς τὸν ὄχλον· ὡμολόγησα δʼ εἰς τήμερον παρέσεσθαι. ταῦτα δὴ ἐκαλλωπισάμην, ἵνα καλὸς παρὰ καλὸν ἴω. ἀλλὰ σύ, ἦ δʼ ὅς, πῶςἔχεις πρὸς τὸ ἐθέλειν ἂν ἰέναι ἄκλητος ἐπὶ δεῖπνον;

#Ἀριστόδημος:
κἀγώ,εἶπον ὅτι οὕτως ὅπως ἂν σὺ κελεύῃς.

#Σωκράτης:
ἕπου τοίνυν,ἵνα καὶ τὴν παροιμίαν διαφθείρωμεν μεταβαλόντες, ὡς ἄρα καὶἈγάθωνʼ ἐπὶ δαῖτας ἴασιν αὐτόματοι ἀγαθοί. Ὅμηρος μὲν γὰρ κινδυνεύει οὐ μόνον διαφθεῖραι ἀλλὰ καὶ ὑβρίσαι εἰς ταύτην τὴν παροιμίαν· ποιήσας γὰρ τὸν Ἀγαμέμνονα διαφερόντως ἀγαθὸν ἄνδρατὰ πολεμικά, τὸν δὲ Μενέλεωνμαλθακὸν αἰχμητήν, θυσίαν ποιουμένου καὶ ἑστιῶντος τοῦ Ἀγαμέμνονος ἄκλητον ἐποίησεν ἐλθόντα τὸν Μενέλεων ἐπὶ τὴν θοίνην, χείρω ὄντα ἐπὶ τὴν τοῦ ἀμείνονος.

#Ἀριστόδημος:
ἴσως μέντοι κινδυνεύσω καὶ ἐγὼ οὐχ ὡς σὺ λέγεις, ὦ Σώκρατες, ἀλλὰ καθʼ Ὅμηρον φαῦλος ὢν ἐπὶ σοφοῦ ἀνδρὸς ἰέναι θοίνην ἄκλητος. ὅρα οὖν ἄγων με τί ἀπολογήσῃ, ὡς ἐγὼ μὲν οὐχ ὁμολογήσω ἄκλητοςἥκειν, ἀλλʼ ὑπὸ σοῦ κεκλημένος.

#Σωκράτης:
σύν τε δύʼ, ἐρχομένω πρὸ ὁδοῦ βουλευσόμεθα ὅτι ἐροῦμεν. ἀλλʼ ἴωμεν.
Датасет
ЛИТЕРАТУРА

Brandwood, L. (1990). The Chronology of Plato's Dialogues. Cambridge: Cambridge University Press

Gerard R. Ledger (1989) Re-Counting Plato: A Computer Analysis of Plato's Style. Oxford: Clarendon Press métaphysique et de morale, 80, 507-523.

Sansone, D. (2018). Stylistic characterization in Plato: Nicias, Alcibiades, and Laches. Greek Roman Byzantine Studies, 58: 156–76.

Tarrant, H. (2013) Stylistic Difference in the Speeches of the Symposium

Tarrant, H. (2013). Socrates' other voices: 'Euthyphro' in the Cratylus. Revue de

Tarrant, Harold & Benitez, Eugenio & Roberts, Terry. (2011). The Mythical Voice in the Timaeus-Critias: Stylometric Indicators. Ancient Philosophy. 31. 95-120.