Очистка цитаты из одной из величайших когда-либо написанных книг.

Для проекта, над которым я работаю, мне нужны цитаты из основополагающей работы Джорджа Оруэлла 1984.

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

Я рассмотрел парсинг данных до, поэтому не буду касаться этого, а вместо этого сосредоточусь на том, как я очищал эти кавычки, превращая их в более читаемый шрифт.

📚

Начиная

Вот одна из цитат, взятых из Goodreads (строки документации добавлены мной для этого примера):

"""      “You are a slow learner, Winston.""How can I help it? How can I help but see what is in front of my eyes? Two and two are four.""Sometimes, Winston. Sometimes they are five. Sometimes they are three. Sometimes they are all of them at once. You must try harder. It is not easy to become sane.”
―
George Orwell,
1984"""

Как видите, есть несколько проблем:

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

Давайте напишем функцию для очистки этой цитаты.

Мы будем использовать только модуль copy из стандартной библиотеки, поэтому давайте импортируем его в наш скрипт, скопируем и вставим этот пример цитаты:

В строке 10 я реализовал оператор raise, чтобы при случайном вызове этой функции возникала ошибка NotImplementedError. Несмотря на то, что мы собираемся приступить к написанию этой функции и вряд ли будем ее вызывать, это все же хорошая практика, к которой стоит привыкнуть.

Зачистка белого пространства

Давайте решим проблему №1, используя метод strip() для начальных символов:

Давайте попробуем:

test = clean_quote(example_quote)
print(test)

Выход:

“You are a slow learner, Winston.""How can I help it? How can I help but see what is in front of my eyes? Two and two are four.""Sometimes, Winston. Sometimes they are five. Sometimes they are three. Sometimes they are all of them at once. You must try harder. It is not easy to become sane.”
    ―
  
    George Orwell,
1984

Выглядит лучше, но нам еще многое предстоит сделать.

Удаление метаданных книги

Итак, давайте рассмотрим, что нам нужно сделать. Нам нужно убедиться, что каждая строка диалога находится на отдельной строке. Мы можем сделать это, вставив символ «\n», чтобы создать новую строку.

Например:

greeting = """
“You are a slow learner, Winston."\n"How can I help it? How can I help but see what is in front of my eyes? Two and two are four."
"""

Выход:

"You are a slow learner, Winston."
"How can I help it? How can I help but see what is in front of my eyes? Two and two are four."

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

К счастью, есть решение! Мы знаем, что нам нужно вставлять символ новой строки после каждой второй кавычки, как в приведенном выше примере (не забывайте игнорировать символы строки документации).

В нашей функции давайте создадим список всех различных кавычек, присутствующих в этой цитате:

Что нам нужно сделать дальше, так это найти положение каждой кавычки в нашей цитате, чтобы мы знали, куда вставить символ новой строки:

То, что я сделал в строке 6, известно как понимание списков, что является удобным однострочником для создания списков. Я передал нашу строку quote функции enumerate(), которая возвращает целое число для индекса и элемента по этому индексу.

Использование enumerate() является примером Pythonicкода.

Не забывайте, что строка — это итерируемый объект, а это означает, что, как и в случае со списком, вы можете перебирать элементы строки. Используя enumerate(), мы можем получить индекс указанных символов в нашей строке quote.

Так здорово, у нас есть список индексов, в которых расположены кавычки.

Но прежде чем вставлять новые строки, давайте удалим метаданные этой книги из цитаты. Под метаданными я подразумеваю следующую информацию в конце нашей строки (выделено жирным шрифтом):

"...It is not easy to become sane."
    ―
  
    George Orwell,
1984

Для этого мы создадим срез строки. Вы используете синтаксис фрагмента [:] для создания новых строк или списков из существующего объекта. Например, чтобы создать список только из двух средних элементов («Желтый» и «Зеленый») в следующем списке, мы должны сделать следующее:

2 — это начальный индекс, а 4 — конечный индекс (примечание: не включен в новый список) того, что мы хотим в нашем новом списке.

Обратите внимание, что синтаксис среза создает поверхностную копию. Подробнее здесь.

Мы собираемся сделать то же самое с цитатой из нашей книги, используя позицию последней кавычки (которая была захвачена в нашем списке character_mapping), чтобы помочь нам разрезать в нужном месте:

Здесь происходит несколько вещей, поэтому давайте разберем их.

Начиная с строки 10, я создал переменную, которая указывает на последний элемент в списке character_mapping, используя оператор индекса [-1].

Этот последний элемент является последней кавычкой в ​​цитате из нашей книги. Мы знаем, что все, что следует за этой последней кавычкой, является метаданными книги. Однако я также увеличил значение этой переменной на 1, чтобы гарантировать, что при разрезании цитаты из книги мы получим последнюю кавычку.

В строке 13 я создал неглубокую копию цитаты из нашей книги, начиная с первого элемента этой строки и заканчивая одним символом послепоследней кавычки.

Как видите, все метаданные книги/информация об авторе были удалены из цитаты:

“You are a slow learner, Winston.""How can I help it? How can I help but 
see what is in front of my eyes? Two and two are four.""Sometimes, Winston. 
Sometimes they are five. Sometimes they are three. Sometimes they are all 
of them at once. You must try harder. It is not easy to become sane.”

Прежде чем мы продолжим, я собираюсь обернуть наш formatted_quote в функцию list(). Это позволит нам вставлять символы по указанным индексам в список, чего мы не можем сделать со строкой из-за ее неизменной природы.

Вставка новых строк

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

“Perhaps one did not want to be loved so much as to be understood.”

Итак, начнем с оценки количества кавычек в цитате с помощью функции len(), которая возвращает количество элементов (длину) в объекте-контейнере.

Если в нашем списке character_mapping больше двух элементов, мы создадим переменную counter с начальным значением 1 (подробнее об этом позже). Затем мы собираемся снова создать цикл for, используя функцию enumerate() :

Обратите внимание, что я различаю list_index и quotation_mark_index.

List_index — это позиция наших кавычек в нашем списке character_mapping, а quotation_mark_index — соответствующее значение в этом списке, которое, как мы знаем, говорит нам, в каком индексе в строке цитаты нашей книги расположены кавычки.

Почему я это делаю? Ну, мы собираемся использовать арифметический оператор, чтобы определить, в какой кавычке вставить новую строку. Что я имею в виду?

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

“
You are a slow learner, Winston."
"
How can I help it? How can I help but see what is in front of my eyes? Two and two are four."
"
Sometimes, Winston. Sometimes they are five. Sometimes they are three. Sometimes they are all of them at once. You must try harder. It is not easy to become sane.”

Итак, когда делатьнам нужно вставить символ новой строки? Ну, после каждой секундной кавычки. Или, другими словами, каждый индекс с нечетным номером в нашем списке character_mapping, отсюда и функция enumerate(), которую мы используем.

Нечетное число? Вы имеете в виду четное число? Нет, потому что не забывайте, что Python — это язык с нулевым индексом, что означает, что он начинает отсчет с 0. Таким образом, наша первая кавычка фактически находится в нашем списке character_mapping с индексом 0, а наша вторая кавычка расположена с индексом 2 и т. д. .

И как мы определяем, является ли индекс четным или нет? Ну, мы можем использовать оператор по модулю %, который возвращает остаток от деления левого операнда на правый операнд. Если целое число без остатка делится на 2 без остатка (например, 0), то оно четное. Если это так, мы не хотим ничего делать, но если индекс на самом деле является нечетным числом, мы знаем, куда вставить новую строку:

Вы заметите, что в строке 19 я увеличил quotation_mark_index на 1. Это нужно для того, чтобы символ новой строки вставлялся после кавычки, а не перед ней.

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

Например, позиция индекса цвета «Красный» меняется после того, как я вставляю «Зеленый»:

colours = ['Blue', 'Red', 'Yellow']
print(colours.index('Red'))

Выход: 1

colours.insert(1,'Green')
print(colours.index('Red'))

Выход: 2

Отсюда и переменная-счетчик, которая, чтобы компенсировать вставку нового символа, увеличивает значение quotation_mark_index на 1.

И, ну, это очень много!

Мы собираемся закрыть нашу функцию, объединив все элементы в нашем formatted_quote list вместе, а затем вернув эту строку:

Давайте попробуем!

print(format_quote(book_quote))

Выход:

«Ты плохо учишься, Уинстон».
«Что я могу поделать? Как я могу не видеть то, что находится перед моими глазами? Два плюс два — четыре.
«Иногда, Уинстон. Иногда их пять. Иногда их три. Иногда они все сразу. Вы должны стараться больше. Нелегко стать разумным».

Если вам понравилась эта статья, пожалуйста, подпишитесь на меня. Каждую неделю я буду изучать по крайней мере один модуль из стандартной библиотеки, а также публиковать учебные пособия для забавных проектов, таких как извлечение из Википедии информации о матчах чемпионата мира по футболу 2022 года или написание скрипта Python для проверки метаданных файлов и изменения содержимого каталога. соответственно".

🐍