Как удалить символы в списке?

Следующая команда при запуске в 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

Как удалить все соответствующие символы, включая «», если они присутствуют?

🤔 А знаете ли вы, что...
Python подходит для начинающих программистов благодаря своей простоте и читаемости кода.


1
142
3

Ответы:

Решено

Ваш файл начинается с 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

Вы можете сделать это в 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() ) )