Попробуйте, кроме как в Python

#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 . Также обратите внимание, что my if 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: Я не думаю, что мы говорим здесь о производственной среде, поэтому я бы сказал, что это не проблема.