Удаление знаков препинания и создание словаря Python

Я пытаюсь создать функцию, которая удаляет знаки препинания и строчные буквы для каждой буквы в строке. Затем он должен вернуть все это в виде словаря, который подсчитывает частоту слов в строке.

Это код, который я написал до сих пор:

def word_dic(string):
    string = string.lower()
    new_string = string.split(' ')
    result = {}

    for key in new_string:
        if key in result:
            result[key] += 1
        else:
            result[key] = 1

    for c in result:
        "".join([ c if not c.isalpha() else "" for c in result])

    return result

Но вот что я получаю после его выполнения:

{'am': 3,
 'god!': 1,
 'god.': 1,
 'i': 2,
 'i?': 1,
 'thanks': 1,
 'to': 1,
 'who': 2}

Мне просто нужно убрать знаки препинания в конце слов.


person Miguel 2488    schedule 24.03.2018    source источник


Ответы (4)


"".join([ c if not c.isalpha() else "" for c in result]) создает новую строку без знаков препинания, но ничего не делает с ней; его сразу же выбрасывают, потому что вы никогда не сохраняете результат.

На самом деле, лучший способ сделать это - нормализовать ключи перед подсчетом их в result. Например, вы можете сделать:

for key in new_string:
    # Keep only the alphabetic parts of each key, and replace key for future use
    key = "".join([c for c in key if c.isalpha()])
    if key in result:
        result[key] += 1
    else:
        result[key] = 1

Теперь result никогда не имеет ключей с пунктуацией (и счетчики для "god." и "god!" суммируются только под ключом "god"), и нет необходимости в другом проходе для удаления знаков препинания постфактум.

В качестве альтернативы, если вы заботитесь только о начальной и конечной пунктуации в каждом слове (поэтому "it's" следует сохранить как есть, а не преобразовывать в "its"), вы можете еще больше упростить. Просто import string, затем измените:

    key = "".join([c for c in key if c.isalpha()])

to:

    key = key.rstrip(string.punctuation)

Это соответствует тому, что вы конкретно просили в своем вопросе (удалите знаки препинания в конце слова, но не в начале и не вставьте в слово).

person ShadowRanger    schedule 24.03.2018
comment
Проголосовали за включение опций. Defaultdict int создаст более компактный код, верно? - person Anton vBR; 24.03.2018
comment
@AntonvBR: Да. И collections.Counter был бы более понятным (с аналогичным поведением). Тем не менее, даже без defaultdict(int) (или любого импорта) вы могли бы сделать result[key] = result.get(key, 0) + 1 и избежать четырехстрочного LBYL в пользу однострочного. - person ShadowRanger; 24.03.2018
comment
Привет!! Я очень признателен за вашу помощь :) Код, предоставленный ShadowRanger, действительно дал то, что я хотел. Меня раздражает то, что я видел, что я был рядом, чтобы получить его, я просто забыл сохранить часть .join в переменной. В следующий раз я уделю больше внимания. Большое спасибо, ребята !! - person Miguel 2488; 24.03.2018

Другой вариант - использовать прилагаемые батареи известного Python.

>>> sentence = 'Is this a test? It could be!'
>>> from collections import Counter
>>> Counter(re.sub('\W', ' ', sentence.lower()).split())
Counter({'a': 1, 'be': 1, 'this': 1, 'is': 1, 'it': 1, 'test': 1, 'could': 1})

Использует collections.Counter для подсчета слов и _ 3_ для замены всего, кроме словесного символа.

person randomir    schedule 24.03.2018
comment
Хорошо (+1), но для удобства чтения я бы использовал больше строк и переменных. - person Anton vBR; 24.03.2018
comment
Преобразование не-словных символов в пробелы с последующим разделением заставит "it's" обрабатываться как слова "it" и "s". Обычно вы хотите разделить на пробелы, а затем удалить знаки препинания или разделить знаки препинания и разделить их по пробелам, а не преобразовывать знаки препинания в пробелы. - person ShadowRanger; 24.03.2018

Вы можете использовать string.punctuation для распознавания знаков препинания и использовать collections.Counter для подсчета случаев, когда строка правильно разложена.

from collections import Counter
from string import punctuation

line = "It's a test and it's a good ol' one."

Counter(word.strip(punctuation) for word in line.casefold().split())
# Counter({"it's": 2, 'a': 2, 'test': 1, 'and': 1, 'good': 1, 'ol': 1, 'one': 1})

Использование str.strip вместо str.replace позволяет сохранить такие слова, как Это.

Метод str.casefold - это просто более общий случай str.lower.

person Olivier Melançon    schedule 24.03.2018

Возможно, если вы захотите повторно использовать слова позже, вы можете сохранить их во вложенном словаре вместе с его номером вхождения. Каждое слово будет иметь свое место в словаре. Мы можем создать нашу собственную функцию для удаления знаков препинания, довольно просто. Посмотрите, соответствует ли приведенный ниже код вашим потребностям:

def remove_punctuation(word):
    for c in word:
        if not c.isalpha():
            word = word.replace(c, '')
    return word


def word_dic(s):
    words = s.lower().split(' ')
    result = {}

    for word in words:
        word = remove_punctuation(word)

        if not result.get(word, None):
            result[word] = {
                'word': word,
                'ocurrences': 1,
            }
            continue
        result[word]['ocurrences'] += 1  

    return result


phrase = 'Who am I and who are you? Are we gods? Gods are we? We are what we are!'
print(word_dic(phrase))

и вы получите такой результат:

{ 'who': { 'word': 'who', 'ocurrences': 2}, 'am': { 'word': 'am', 'ocurrences': 1}, 'i': { 'word': 'i', 'ocurrences': 1}, 'and': { 'word': 'and', 'ocurrences': 1}, 'are': { 'word': 'are', 'ocurrences': 5}, 'you': { 'word': 'you', 'ocurrences': 1}, 'we': { 'word': 'we', 'ocurrences': 4}, 'gods': { 'word': 'gods', 'ocurrences': 2}, 'what': { 'word': 'what', 'ocurrences': 1} }

Затем вы можете легко получить доступ к каждому слову и его вхождениям, просто выполнив:

word_dict(phrase)['are']['word']       # output: are
word_dict(phrase)['are']['ocurrences'] # output: 5
person R.R.C.    schedule 24.03.2018
comment
вау, это какой-то мастер-код !! большое спасибо, это помогло и многому меня научило !! :) - person Miguel 2488; 24.03.2018
comment
@ Miguel2488, без проблем. - person R.R.C.; 24.03.2018