Примитивный чат-бот Python IRC для twitch

В настоящее время я работаю над ботом IRC для Twitch.tv, и мне интересно, как я могу реализовать список запрещенных слов? Вот что у меня есть до сих пор, и я в тупике из-за своих ограниченных знаний о питоне. До сих пор все работает отлично, за исключением проверки наличия запрещенных слов в сообщении. Это бит кода, о котором идет речь:

if bannedWords.split in message:
                sendMessage(s, "/ban " + user)
                break

Я думал проверить список, чтобы увидеть, содержит ли сообщение что-нибудь из списка?

bannedWords = ["badword1", "badword1"]

Но я просто не уверен..

import string
from Read import getUser, getMessage
from Socket import openSocket, sendMessage
from Initialize import joinRoom

s = openSocket()
joinRoom(s)
readbuffer = ""
bannedWords = ["badword1", "badword1"]
while True:
        readbuffer = readbuffer + s.recv(1024)
        temp = string.split(readbuffer, "\n")
        readbuffer = temp.pop()

        for line in temp:
            print(line)
            if "PING" in line:
                s.send(line.replace("PING", "PONG"))
                break
            user = getUser(line)
            message = getMessage(line)
            print user + " typed :" + message
            if bannedWords.split in message:
                sendMessage(s, "/ban " + user)
                break

Заранее спасибо!!


person Aaron    schedule 01.04.2016    source источник
comment
BannedWords - это определенный вами список запрещенных слов?   -  person Banach Tarski    schedule 01.04.2016
comment
Просто слова, которые я добавляю. Сначала я как бы пытаюсь не торопиться. В конце концов, может быть, я могу добавить команду для записи слов в .txt, а затем читать их?   -  person Aaron    schedule 01.04.2016
comment
Вы тоже забыли вызвать split, вы спрашиваете, есть ли в сообщении ссылка на str.split   -  person Padraic Cunningham    schedule 01.04.2016
comment
Похоже, что temp.pop() тоже может быть проблемной зоной...   -  person Jon Clements♦    schedule 01.04.2016
comment
Обязательная ссылка: Проблема Сканторпа. Тщательно подумайте о том, насколько жесткой должна быть ваша система фильтрации, потому что в конечном итоге вы можете заглушить законный разговор.   -  person Kevin    schedule 01.04.2016
comment
@Kevin Спасибо за ссылку, интересно!   -  person Aaron    schedule 01.04.2016
comment
@Xarotic, вы уже создали список из bannedWords, когда вы .split() его изначально... (ваш """.split()...)   -  person Jon Clements♦    schedule 01.04.2016
comment
Вы не должны редактировать ответы на свой вопрос. Это мешает будущим читателям понять, что происходит.   -  person Ilja Everilä    schedule 01.04.2016
comment
@ Илья, я вернул его к оригиналу! Извини!   -  person Aaron    schedule 01.04.2016
comment
@Xarotic, не беспокойся об этом, просто дружеское напоминание. Хороший вопрос, вероятно, прочитают многие другие позже, поэтому, если их проблема похожа на вашу, лучше оставить ее нетронутой и позволить ответам объясниться самим собой.   -  person Ilja Everilä    schedule 01.04.2016


Ответы (2)


Если вам нужны точные совпадения, используйте набор слов, вызовите lower в строке и проверьте, является ли набор неверных слов непересекающимся или нет:

banned_set = {"badword1", "badword2"}
if banned_set.isdisjoint(message.lower().split())
   # no bad words

если "foo" было запрещённым, а "foobar" было совершенно правильным, то использование in/__contains__ приведет к неправильной фильтрации слов, поэтому вам нужно тщательно решить, какой путь выбрать.

если banned_set.isdisjoint(message.lower().split()) оценивается как True, можно продолжать:

In [3]: banned_set = {"badword1", "badword2"}

In [4]: banned_set.isdisjoint("foo bar".split())
Out[4]: True

In [5]: banned_set.isdisjoint("foo bar badword1".split())
Out[5]: False
person Padraic Cunningham    schedule 01.04.2016
comment
Хорошее замечание по поводу "foo" против "foobar", совсем пропустил это. - person Ilja Everilä; 01.04.2016
comment
@Padraic Cunningham Спасибо, это имеет для меня гораздо больше смысла! - person Aaron; 01.04.2016
comment
Проблема, с которой я сталкиваюсь при использовании этого решения, заключается в том, что оно пытается забанить любого, кто говорит что-либо, кроме слов в Banned_set. - person Aaron; 01.04.2016
comment
В вашем старом коде тест был другим. Там, где вы проверяли, действительно ли сообщение содержит нецензурные слова, это решение проверяет отсутствие нецензурных слов. - person Ilja Everilä; 01.04.2016
comment
@Xarotic, все верно, если banned_set.isdisjoint(message.lower().split()) оценивается как True, то плохих слов нет. - person Padraic Cunningham; 01.04.2016
comment
Я только что понял свою ошибочную логику! Это плохой способ сделать это? if banned_set.isdisjoint(message.lower().split()): break else: sendMessage(s, "/ban " + user) - person Aaron; 01.04.2016
comment
Я явно не знаю, как правильно комментировать код.. но я надеюсь, вы понимаете, что я имею в виду о if-else - person Aaron; 01.04.2016
comment
@Xarotic использует if not - тогда это будет означать, если будут плохие слова... - person Jon Clements♦; 01.04.2016
comment
@Xarotic, вы можете использовать if not banned_set.isdisjoint(message.lower().split()): sendMessage(s, "/ban " + user) и сломать, остальное не нужно. если not banned_set.isdisjoint(.. оценивается как True, то это плохие слова. - person Padraic Cunningham; 01.04.2016
comment
@PadraicCunningham Большое спасибо. Я явно больший нуб, чем я думал! - person Aaron; 01.04.2016
comment
@Xarotic, не беспокойтесь, это может немного сбить с толку. - person Padraic Cunningham; 01.04.2016

Предполагая, что message и bannedWords являются строками:

if any(map(message.__contains__, bannedWords.split())):
    ...

Если, с другой стороны, bannedWords уже является списком, как в вашем примере кода, пропустите разбиение (на самом деле тип list не имеет метода split):

if any(map(message.__contains__, bannedWords)):
    ...

Это проверит, существует ли какое-либо из запрещенных слов в любой части строки; "The grass is greener on the other side." будет соответствовать запрещенным словам, таким как "ass".

Обратите внимание, что map ведет себя по-разному в двух основных версиях Python:

  • В Python 2 map создает list, что сводит на нет преимущества короткого замыкания any. Вместо этого используйте выражение генератора: any(word in message for word in bannedWords).
  • В Python 3 map создает итератор, который будет лениво применять функцию к данному итерируемому объекту.

P.s.

Что касается bannedWords.split(), обычно можно увидеть списки слов и т. д., сгенерированные в python с использованием многострочных строковых литералов, например:

bannedWords = """
banned
words
are
bad
mmkay
""".split()
person Ilja Everilä    schedule 01.04.2016
comment
Я, собственно, и это пробовал, но почему-то как только в чат набирается одно из запрещенных слов, бот вылетает. Может моя реализация неверна? - person Aaron; 01.04.2016
comment
@Xarotic Из вашего вопроса не совсем понятно, что вам нужно. Добавьте полученные трассировки и переформулируйте свой вопрос. - person Ilja Everilä; 01.04.2016
comment
Кроме того, вы имеете в виду, что вы пробовали этот тип решения раньше, или вы попробовали решение этого ответа сейчас и получили новое исключение из другого места? - person Ilja Everilä; 01.04.2016
comment
@Ilja Использование map будет отличаться в версиях 2.x и 3.x (не говоря уже о том, что вызов методов dunder без необходимости просто выглядит болезненно) - вы можете сделать это последовательным и столь же понятным, используя: if any(word in message for word in bannedWords) - person Jon Clements♦; 01.04.2016
comment
@JonClements это не будет существенно отличаться, если только не будет тысяч и тысяч запрещенных слов. Другой будет проверять список, другой - итерируемый. Конечный результат тот же. - person Ilja Everilä; 01.04.2016
comment
@Ilja в 2.x map сначала материализует список, что нарушает преимущество быстрого поведения any... (конечно, конечный результат тот же, и только для короткого списка bannedWords это не имеет значения, но если вы масштабируете это до большого, большого количества, вы создаете нежелательный список) - person Jon Clements♦; 01.04.2016
comment
@JonClements не был явным образом после поведения ярлыка. Кроме того, я больше не поддерживаю продвижение решений Python 2, если только OP четко не заявит о намерении его использовать. Здесь у нас нет такого четкого намерения, так как печать используется как функция, а теги отсутствуют. - person Ilja Everilä; 01.04.2016
comment
@Ilja Вопрос об использовании методов dunder остается в силе - и, кроме того, почему бы не написать код, который ведет себя одинаково в разных версиях и является более читаемым? :п - person Jon Clements♦; 01.04.2016
comment
@JonClements, ты заставил меня использовать дандер, это не совсем лучшая практика. Но я сопротивляюсь тому, чтобы продвигать решения python3 ради поддержки версий с python2. Новый код не должен быть написан с учетом python2, за исключением случаев крайней необходимости. По моему мнению. - person Ilja Everilä; 01.04.2016