Следующая команда при запуске в BASH очищает The Raven.
cat The_Raven.txt | gawk '{print tolower($0)}' | tr -d "\!\"#$%&'()*+,-./:;<=>?@[\\]^_\`{|}~"
Следующая команда изменяет The Raven, но делает файл нечитаемым.
cat The_Raven.txt | gawk '{print tolower($0)}' | tr -d "\!\"#$%&'()*+,-./:;<=>?@[\\]^_\`{|}~«»"
Следующий код Python использует subprocess
для очистки «Ворона».
command = "cat The_Raven.txt | gawk '{print tolower($0)}' | tr -d \"!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_\\`{|}~\""
cleaned_text_from_command = subprocess.run(command, shell = True, capture_output = True, text = True, encoding = 'utf-8').stdout
Вставка «»
после ~
в приведенный выше код Python приводит к следующей ошибке.
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: invalid continuation byte
Как удалить все соответствующие символы, включая «»
, если они присутствуют?
Кстати, я рекомендую использовать необработанную строку для command
, чтобы не нужно было удваивать все обратные косые черты.
Почему вы делаете это с помощью подпроцесса? Все, что вы делаете с gawk
и tr
, можно легко сделать в самом Python.
Бармар, я пишу тест, который сравнивает очищенный текст из команды с очищенным текстом из функции, как меня просили.
Я удалил encoding = 'utf-8'
по вашему предложению без изменений. Что касается изменения utf-8
на latin-1
, latin-1
не может кодировать все символы в The Raven. Интересно, что команда BASH делает файл нечитаемым для Python.
Вы можете заменить tr ...
на sed 's/[CHARLIST]//g'
для поддержки UTF-8. Или вы можете использовать функции Python, чтобы сделать то же самое.
Ваша вторая команда никак не изменяет файл. Как это можно сделать нечитабельным?
Почему вы пытаетесь удалить именно этот список персонажей? Вы пытаетесь удалить все знаки препинания или что-то еще? В любом вопросе вы не должны предоставлять образец входных данных без ожидаемого результата, поэтому, если вы собираетесь предоставить всю книгу в качестве образца входных данных, вы должны предоставить «очищенную» всю книгу в качестве ожидаемого результата, но не делайте этого и не делайте этого. Не размещайте ссылки или изображения в вопросах. Вместо этого создайте и опубликуйте минимальный воспроизводимый пример , демонстрирующий вашу проблему, см. Как спросить.
Если вы просто пытаетесь преобразовать все символы в нижний регистр и удалить все символы пунктуации, это будет awk '{gsub(/[[:punct:]]/,""); print tolower($0)}'
в любой POSIX awk. Если вы также хотите удалить управляющие символы, тогда gsub(/[[:punct:][:cntrl:]]/,"")
, а если вам действительно нужно удалить определенный список символов, тогда gsub(/[]!"#$%&\047()*+,./:;<=>?@[\\^_`{|}~-]/,"")
или gsub(/[[:punct:]«»]/,"")
и т. д. Что вам не нужно делать, так это перенаправлять вывод awk
на tr
.
Что касается «делает файл нечитаемым» - отредактируйте свой вопрос, чтобы уточнить, что вы под этим подразумеваете, поскольку ничто в ваших командах оболочки не может сделать входной файл нечитаемым, и они не могут создать выходной файл, который не читается, если только ваша umask настроен на создание файлов, которые вы не сможете прочитать, но я очень сомневаюсь, что это так.
Ваш файл начинается с UTF-8 BOM (ef bb bf
):
$ od -tx1 -N8 pg17192.txt
0000000 ef bb bf 54 68 65 20 50 0000010
Кодировка UTF-8 символа »
содержит байт (bb
) из спецификации:
$ echo '»' | od -tx1
0000000 c2 bb 0a
0000002
Следующий отрывок из man tr
предполагает, что многобайтовые символы могут не поддерживаться:
Полная поддержка доступна только для безопасных однобайтовых локалей, в которых каждый возможный входной байт представляет собой один символ.
И быстрый тест показывает, что это действительно так; tr -d
считает каждый байт символом и разбивает спецификацию (bb
отсутствует):
$ tr -d '»' <pg17192.txt | od -tx1 -N8
0000000 ef bf 54 68 65 20 50 72
0000010
Этого можно избежать, используя инструмент, поддерживающий многобайтовые символы:
$ sed 's/»//g' pg17192.txt | od -tx1 -N8
0000000 ef bb bf 54 68 65 20 50
0000010
Также стоит отметить, что tr -d '»'
будет работать с реализацией tr
BSD, поскольку он обрабатывает символы UTF-8 (как того требует POSIX). Я предполагаю, что вы тестируете здесь GNU tr
, который не обрабатывает многобайтовые символы. Однако не уверен, как обстоят дела в других реализациях tr
.
Вы можете сделать это в Python с помощью чего-то вроде этого, отфильтровав из файла все небуквенно-цифровые символы и преобразуя их в нижний регистр.
#! /usr/bin/env python3
import itertools
with open("pg17192.txt") as file:
print(''.join((map(str.lower, filter(lambda c: c.isspace() or c.isalnum(), itertools.chain.from_iterable(l for l in file))))))
Некоторые наблюдения -
УУоК. gawk
вполне способен читать файл, не вызывая еще один процесс, у которого нет другой цели, кроме как передать данные на стандартный ввод. Используйте awk '{yourcode}' file
или даже awk '{yourcode}' < file
(операционная система прикрепит файл на стандартный ввод без cat
).
Точно так же awk
выполнит все эти подавления символов, не вызывая отдельный экземпляр tr
. Для такой небольшой работы это не имеет большого значения, но стоит выработать привычку отрезать ненужные фрагменты, когда вам предстоит более крупная работа, требующая большей эффективности. Практикуйтесь в малом, чтобы быть готовым к большому.
С другой стороны этого аргумента, если я не ошибаюсь, похоже, что вы просто убираете все знаки препинания. Если это правда, то для этого уже существует оптимизированный класс символов POSIX. Вероятно, вы сможете получить то, что хотите, с помощью
awk '{print tolower(gensub(/[[:punct:]]/,"","g")) }' The_Raven.txt
...но если вы уже работаете на Python, зачем вам раскошелиться на awk
?
import re
with open('The_Raven.txt', encoding = "utf-8" ) as file:
print( re.sub( '[^\s\w]', '', file.read() ) )
Не используйте
encoding='utf-8'
, так как вывод не кодируется таким образом.