Логическая ошибка при разборе файла с python: KeyError: 'O' - PullRequest
2 голосов
/ 22 января 2012

, поэтому я пытаюсь открыть текстовый файл со стихотворением и посмотреть, сколько раз я могу произнести слово «ХОРОШО» по буквам в текстовом файле в каждой строке, но я получаю следующую ошибку:

Traceback (most recent call last):
  File "./soup.py", line 11, in <module>
    print( "\n".join( [("Case #%d: %d" % (i, parse(file[i]))) for i in range(1, len(file))]))
  File "./soup.py", line 7, in parse
    d['O'] /= 2
KeyError: 'O'

источник:

#!/usr/bin/python

def parse(string):
    d = {'G' : 0, 'O' : 0, 'D' : 0}
    d = {s: string.count(s) for s in string if s in d } 
    d['O'] /= 2
    return min(d.values())

file = open("poem.txt").read().split('\n')
print( "\n".join( [("Case #%d: %d" % (i, parse(file[i]))) for i in range(1, len(file))]))

Ответы [ 4 ]

4 голосов
/ 22 января 2012

FWIW, я написал бы это, используя объект Counter:

from collections import Counter

def spellcount(string, wanted):
    wanted_counts = Counter(wanted)
    have_counts = Counter(string)
    return min(have_counts[c]//wanted_counts[c] for c in wanted_counts)

wanted = "GOOD"
with open("poem.txt") as fp:
    for i, line in enumerate(fp):
        print("Case", i, ":", spellcount(line, wanted))

Счетчик ведет себя как defaultdict, например,

>>> from collections import Counter
>>> Counter('GOOD')
Counter({'O': 2, 'G': 1, 'D': 1})
>>> Counter('GOOD')['i']
0
3 голосов
/ 22 января 2012

Вы уверены, что ваша строка 7 читает d ['O']?

В сообщении об ошибке предлагается, что она читает d ['C']

Проблема в том, что если строка не содержитСимволы «O», затем «O» не будут в d, и это приведет к ошибке.

При втором определении d будет создан новый словарь, который не будет содержать клавишу «O».

def parse(string):
    d = {'G' : 0, 'O' : 0, 'D' : 0}
    d = {s: string.count(s) for s in string if s in d }
    try:
        d['O'] /= 2
    except KeyError:
        return 0
    return min(d.values())

file = open("test1.py").read().split('\n')
print( "\n".join( [("Case #%d: %d" % (i, parse(file[i]))) for i in range(1, len(file))]))

(может оказаться более эффективным сделать d = {s: string.count (s) для s в d})

(мне также нравится альтернативное предложение использования collection.Counter.Однако, если вас интересует скорость, тогда мои измерения времени показывают, что для строки длиной 10 миллионов символов создание объекта Counter занимает 3 секунды, но только 0,012 секунды на вызов string.count)

1 голос
/ 22 января 2012

Используйте 'GOD' вместо string в вашем словаре, потому что не каждая строка будет содержать 'O'.

def parse(string):
    d = {s: string.count(s) for s in 'GOD'}
    d['O'] /= 2
    return min(d.values())
0 голосов
/ 22 января 2012

Проблема в том, что если вы столкнетесь с линией, в которой нет буквы «О», этот ключ не будет существовать. Вы можете решить эту проблему, используя dict.get. dict.get не вызывает исключение, если ключ не существует, но возвращает второй аргумент, в этом случае 0:

def parse(string):
    d = {s: string.count(s) for s in string if s in 'GOD'} 
    d['O'] = d.get('O', 0) / 2
    return min(d.values())

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

def parse(string):
    string = string.upper()
    d = {s: string.count(s) for s in string if s in 'GOD'} 
    d['O'] = d.get('O', 0) / 2
    return min(d.values())

Редактировать

Конечно, использование d = {s: string.count(s) for s in 'GOD'} полностью исключает проблему и является более кратким. Я предлагаю использовать ответ @ Gandaro.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...