Эффективный способ поиска недопустимых символов в python - PullRequest
1 голос
/ 18 апреля 2011

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

def clean_topic_message(self):
    topic_message = self.cleaned_data['topic_message']
    words = topic_message.split()
    if (topic_message == ""):
        raise forms.ValidationError(_(u'Please provide a message for your topic'))
    ***for word in words:
        if (re.match(r'[^<>/\{}[]~`]$',topic_message)):
            raise forms.ValidationError(_(u'Topic message cannot contain the following: <>/\{}[]~`'))***
    return topic_message

Спасибо за любую помощь.

Ответы [ 9 ]

5 голосов
/ 18 апреля 2011

Для решения регулярных выражений здесь есть два пути:

  1. Найдите один недопустимый символ в любом месте строки.
  2. Проверка каждого символа в строке.

Вот скрипт, который реализует оба:

import re
topic_message = 'This topic is a-ok'

# Option 1: Invalidate one char in string.
re1 = re.compile(r"[<>/{}[\]~`]");
if re1.search(topic_message):
    print ("RE1: Invalid char detected.")
else:
    print ("RE1: No invalid char detected.")

# Option 2: Validate all chars in string.
re2 =  re.compile(r"^[^<>/{}[\]~`]*$");
if re2.match(topic_message):
    print ("RE2: All chars are valid.")
else:
    print ("RE2: Not all chars are valid.")

Выберите.

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

Тесты: После того, как я увидел интересное решение gnibbler с использованием set(), мне было интересно узнать, какой из этих методов будет наиболее быстрым, поэтому я решил измерить их. Вот измеренные контрольные данные и утверждения и значения результата timeit:

Данные испытаний:

r"""
TEST topic_message STRINGS:
ok:  'This topic is A-ok.     This topic is     A-ok.'
bad: 'This topic is <not>-ok. This topic is {not}-ok.'

MEASURED PYTHON STATEMENTS:
Method 1: 're1.search(topic_message)'
Method 2: 're2.match(topic_message)'
Method 3: 'set(invalid_chars).intersection(topic_message)'
"""

Результаты:

r"""
Seconds to perform 1000000 Ok-match/Bad-no-match loops:
Method  Ok-time  Bad-time
1        1.054    1.190
2        1.830    1.636
3        4.364    4.577
"""

Тесты производительности показывают, что вариант 1 немного быстрее, чем вариант 2, и оба намного быстрее, чем метод set().intersection(). Это верно для строк, которые совпадают и не совпадают.

2 голосов
/ 18 апреля 2011

При использовании регулярных выражений нужно быть намного осторожнее - они полны ловушек.

в случае [^<>/\{}[]~] первый ] закрывает группу, которая, вероятно, не соответствует вашим ожиданиям. Если вы хотите использовать ] в группе, это должен быть первый символ после [, например []^<>/\{}[~]

простой тест подтверждает это

>>> import re
>>> re.search("[[]]","]")
>>> re.search("[][]","]")
<_sre.SRE_Match object at 0xb7883db0>

регулярное выражение в любом случае излишне для этой проблемы

def clean_topic_message(self):
    topic_message = self.cleaned_data['topic_message']
    invalid_chars = '^<>/\{}[]~`$'
    if (topic_message == ""):
        raise forms.ValidationError(_(u'Please provide a message for your topic'))
    if set(invalid_chars).intersection(topic_message):
        raise forms.ValidationError(_(u'Topic message cannot contain the following: %s'%invalid_chars))
    return topic_message
2 голосов
/ 18 апреля 2011

re.match и re.search ведут себя по-разному . Разделение слов не требуется для поиска с использованием регулярных выражений.

import re
symbols_re = re.compile(r"[^<>/\{}[]~`]");

if symbols_re.search(self.cleaned_data('topic_message')):
    //raise Validation error
2 голосов
/ 18 апреля 2011

Если эффективность является серьезной проблемой, я бы re.compile () re string, так как вы будете использовать одно и то же регулярное выражение много раз.

1 голос
/ 18 апреля 2011

Я согласен с gnibbler, регулярное выражение является избыточным для этой ситуации.Вероятно, после удаления этих нежелательных символов вы захотите удалить и нежелательные слова, вот несколько простых способов сделать это:

def remove_bad_words(title):
'''Helper to remove bad words from a sentence based in a dictionary of words.
'''
word_list = title.split(' ')
for word in word_list:
    if word in BAD_WORDS: # BAD_WORDS is a list of unwanted words
        word_list.remove(word)
#let's build the string again
title2 = u''
for word in word_list:
    title2 = ('%s %s') % (title2, word)
    #title2 = title2 + u' '+ word

return title2
1 голос
/ 18 апреля 2011

is_valid = not any (k в тексте для k в '<> / {} [] ~ `')

1 голос
/ 18 апреля 2011

Я не могу сказать, что было бы более эффективным, но вам, безусловно, следует избавиться от $ (если это не недопустимый символ для сообщения) ... сейчас вы соответствуете re только если символынаходятся в конце topic_message, потому что $ привязывает совпадение к правой стороне строки.

0 голосов
/ 07 января 2012

Пример: просто с учетом ваших потребностей.

### valid chars: 0-9 , a-z, A-Z only
import re
REGEX_FOR_INVALID_CHARS=re.compile( r'[^0-9a-zA-Z]+' )
list_of_invalid_chars_found=REGEX_FOR_INVALID_CHARS.findall( topic_message )
0 голосов
/ 18 апреля 2011

В любом случае вам необходимо отсканировать все сообщение. Так не будет ли что-нибудь простое, как эта работа?

def checkMessage(topic_message):
  for char in topic_message:
       if char in "<>/\{}[]~`":
           return False
  return True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...