#python
#python
Вопрос:
Я хочу указать путь к файлу, открыть файл и прочитать содержащиеся в нем данные. После этого я хотел бы подсчитать количество вхождений каждой буквы в алфавите.
Из того, что я прочитал и услышал, здесь лучше всего использовать try / except. Я старался изо всех сил в этом, но мне удалось подсчитать количество вхождений букв в строку только в программе, а не в файле.
Я понятия не имею, как это сделать сейчас, и мой мозг начинает болеть …. это то, что у меня есть до сих пор:
import sys
print "Enter the file path:"
thefile = raw_input()
f = open(thefile, "r")
chars = {}
for c in f:
try:
chars[c] =1
except:
chars[c]=1
print chars
Любая помощь будет высоко оценена. Спасибо.
РЕДАКТИРОВАТЬ: Я забыл сказать, что результат, который я получаю на данный момент, говорит о том, что весь файл состоит из одного символа. Файл состоит из «abcdefghijklmnopqrstuvwxyz», и результирующий вывод: {‘»abcdefghijklmnopqrstuvwxyz»n’: 1}, чего не должно быть.
Ответ №1:
Немного более элегантный подход заключается в следующем:
from __future__ import with_statement
from collections import defaultdict
print "Enter the file path:"
thefile = raw_input()
with open(thefile, "r") as f:
chars = defaultdict(int)
for line in f:
for c in line:
chars[c] = 1
print dict(chars)
Это использует a defaultdict
для упрощения процесса подсчета, использует два цикла, чтобы убедиться, что мы читаем каждый символ отдельно без необходимости считывать весь файл в память, и использует with
блок, чтобы гарантировать, что файл закрыт должным образом.
Редактировать:
Для вычисления гистограммы букв вы можете использовать эту версию:
from __future__ import with_statement
from string import ascii_letters
print "Enter the file path:"
thefile = raw_input()
chars = dict(zip(ascii_letters, [0] * len(ascii_letters)))
with open(thefile, "r") as f:
for line in f:
for c in line:
if c in ascii_letters:
chars[c] = 1
for c in ascii_letters:
print "%s: %d" % (c, chars[c])
Здесь используется удобная string.ascii_letters
константа и также показан аккуратный способ создания пустого словаря с использованием zip()
.
Комментарии:
1. Это быстрее и немного короче в использовании
defaultdict(int)
, поскольку это не требует вызова функции Python каждый раз.2. Хм, я получаю ошибку при запуске этого: Трассировка (последний вызов last): File «********************», строка 14, в <module> chars[c] = 1 KeyError: ‘a’ Я довольно новичок в Python, поэтому требуется некоторое время, чтобы вникнуть. И это в 2 часа ночи!
3. @Emlyn: У меня работает. Возможно, вы перезаписываете
chars
словарь пустым dict?4. @Daniel Теперь у меня это работает. Я использовал версию до того, как вы ее обновили, и получил ошибку. Я подробнее изучу то, что вы мне показали, чтобы я полностью это понял. Итак, использование этого метода лучше, чем использование try и except?
5. @Emlyn: Нет ничего плохого в использовании
except KeyError
, если вы действительно не уверены, какие ключи есть в словаре. Но если вы заранее знаете, какие именно ключи там есть, тогда проверка может быть быстрее. Итак, вместоif c in ascii_letters
строки мы могли бы использоватьtry: chars[c] = 1; except KeyError: pass
для игнорирования символов, которых не было вascii_letters
. Также обратите внимание, что myif c in ascii_letters
на самом деле также неоптимален —if c in chars
на самом деле было бы быстрее, потому что вместо этого он может использовать поиск по хэш-таблице. (Хотя в этом случае разница минимальна.)
Ответ №2:
for c in f:
Инструкция обрабатывает ваш файл построчно (для этого и предназначена for
операция над файловым объектом). Поскольку вы хотите обрабатывать его посимвольно, попробуйте изменить это на:
data = f.read()
for c in data:
.read()
Метод считывает все содержимое файла в одну строку, присваивает ее data
, затем for
цикл рассматривает каждый отдельный символ этой строки.
Ответ №3:
На самом деле, вы почти на месте; самое важное, чего вам не хватает, это того, что ваш c
— это не символ, а строка: перебор файла Python дает вам строку за раз. Вы можете решить проблему, добавив еще один цикл:
print "Enter the file path:"
thefile = raw_input()
f = open(thefile, "r")
chars = {}
for line in f:
for c in line:
try:
chars[c] =1
except:
chars[c]=1
print chars
(Чтение всего файла в строку также работает, как упоминается в другом ответе, если ваш файл достаточно мал, чтобы поместиться в памяти.)
Хотя в этом случае это работает, использовать raw не очень хорошая идея except:
, если вы на самом деле не пытаетесь отловить все возможные ошибки. Вместо этого используйте except KeyError:
.
То, что вы пытаетесь сделать, довольно распространено, поэтому есть метод словаря Python и тип данных, которые могут полностью удалить try/except
из вашего кода. Взгляните на setdefault
метод и defaultdict
тип. С помощью любого из них вы можете, по сути, указать, что отсутствующие значения начинаются с 0.
Комментарии:
1. Спасибо всем за быстрые ответы. Николас, спасибо. Это действительно работает. 🙂 Как бы мне отобразить статистику для всех вхождений алфавита, даже если там нет никаких вхождений? Например, если файл содержал текст «Привет. Как дела?», Я бы хотел, чтобы это показывало, что существует 0 вхождений буквы b и т.д. Ах, решат ли это метод setdefault и тип defaultdict?
2. Нет, но вы можете сделать что-то вроде этого:
from string import ascii_letters; for letter in ascii_letters: chars[letter] = 0
. Это даст вам A-Z, a-z.3. @Emlyn: То, что сказал Николас. Но более простой способ сделать то же самое,
chars = dict(zip(ascii_letters, [0] * len(ascii_letters)))
как я показываю в моем обновленном ответе.4. Хех, да, хорошая мысль (хотя это становится немного пугающим. 🙂
Ответ №4:
Давайте применим более питонический способ ради PEP8:
import collections
with open(raw_input(), 'rb') as f:
count = collections.Counter(f.read())
print count
Батарейки в комплекте! 🙂
Комментарии:
1. Коллекции доступны, только если у вас python> = 2.7
2. @mike: Я не думаю, что мы говорим здесь о производственной среде, поэтому я бы сказал, что это не проблема.