# 1
class BrokenEgg(Exception):
pass
# 2
class Brain_breacker:
def __init__(self):
# 3
self.test_exp = ""
self.expect_operator = 0
self.braces = 0
# 4
self.operators = ("!", "&", "|", "==", "_")
self.operator_leters = ("!", "&", "|", "=", "_")
self.prefix_operators = ("!")
self.var_begining = ("x", "y")
def is_var(self, i):
# 5
if self.test_exp[i] in ("x", "y"):
return True
return False
def add_var(self, i):
# 6
return i+1
def check_operator_expection(self, i):
# 7
if self.expect_operator:
raise BrokenEgg("Expect operator after '%s'." % self.test_exp[:i])
def check_other_expection(self, i):
# 8
if not self.expect_operator:
if self.test_exp[i] in self.prefix_operators:
return True
raise BrokenEgg("Don't expect operator after '%s'." % self.test_exp[:i])
def is_operator(self, i):
# 9
if self.test_exp[i] in self.operator_leters:
return True
return False
def add_operator(self, i):
# 10
j = i
buf = ""
while self.test_exp[j] in self.operator_leters:
buf += self.test_exp[j]
j += 1
if buf in self.operators:
return j
else:
raise BrokenEgg("Operator '%s' doesn't exist." % buf)
def start(self, expression):
# 11
self.test_exp = expression
i = 0
while i < len(self.test_exp):
# 12
if self.test_exp[i] == "(":
# 13
self.check_operator_expection(i)
# 14
self.braces += 1
# 15
self.expect_operator = False
# 16
i += 1
# 17
continue
# 18
if self.test_exp[i] == ")":
self.braces -= 1
# 19
self.expect_operator = True
i += 1
continue
# 20
if self.is_var(i):
self.check_operator_expection(i)
i = self.add_var(i)
self.expect_operator = True
continue
# 21
if self.is_operator(i):
self.check_other_expection(i)
self.expect_operator = False
i = self.add_operator(i)
continue
# 22
if self.test_exp[i] == " ":
i += 1
continue
# 23
raise BrokenEgg("Unexpectable simbol '%s'." % self.test_exp[i])
# 24
if self.braces:
raise BrokenEgg("Something wrong with braces.")
return True
# 25
def test(text, i = [0]):
# 26
i[0] += 1
print ">Test number %s:" % i[0]
print "Test expression is '%s'." % text
# 27
bb = Brain_breacker()
# 28
try:
bb.start(text)
print "It's allright with '%s'" % text
except BrokenEgg as e:
print e
print ""
# 29
test("(!x == y & x ! x & !(!x & !y))")
test("(!x + y & x ! x & !(!x & !y))")
test("(!x == y & x = x & !(!x & !y))")
test("(!x == (y) & (x ! x & !(!x & !y)))")
test("(!x == (y & (x ! x & !(!x & !y)))")
1) Создаём класс исключения. (Читать доку по исключениям)
2) Создаём класс с именем Brain_breacker. Для студента имя самое оно. :)
3) Обьявляем конструктор класса. Три пермененные нам понадабятся дальше.
4)
operators - списко операторов которые можно использовать.
prefix_operators - список операторов которые можно использовать как префикс к выражению, или переменной.Например “!х”.
operators_leters - список всех символов из которых могут состоять операторы.
var_begining - список первых символов переменных. Например переменные могут начинаться на прочерк, и букву. Вообще-то это должно быть регулярное выражение, ибо если я захочу реализовать правило описанное предложением ранее, то это будет очень большой список Но в данном случае пойдёт.
5) Метод (так называются функции классов) принимает индекс символа в исходном выражении. Проверяет начинается ли с данного символа переменная. Если да то дальше надо читать переменную.
6) Метод читает переменную и возвращает индекс следующего за именем переменной символа. В данном случае у нас переменные односимвольные, потому метод вообще можно было не создавать. Но если имена переменных будут длинные, то именно в этой функции будет задано правило её чтения.
7) Метод проверяет ожидался ли оператор и если да, то вызывает исключение. Код прерывает исполнение. Исключение ловится ключевым словом except и код продолжает исполнятся аж оттуда.
8) Метод проверет ожидалось ли что-либо иное кроме оператора. Если да, то бросаем исключение. Но. Если же мы получили префиксный оператор, хоть и ожидали не оператор, мы продолжаем выполнение программы.
9) Метод определяет оператор начался, или нет.
10) Метод читает оператор. Возвращает индекс следующего за оператором символа. Если же оператора нет в списке операторов, то генерирует исключение (raise).
11) Итак начинаем проверку выражения. Ставим индекс в ноль, создаём цикл который завершится когда индекс станет больше длины выражения.
12) Если символ открывающей скобки.
13) Вдруг мы в прошлый раз обработали переменную, или закрывающую скобку, и ожидали увидеть дальше оператор? Вот и проверяем, а не ожидался ли оператор? Если да то выражение ошибочно, и мы должн вывести соответствующее сообщение. (смотреть №7)
14) Увеличим счётчик скобок.
15) За открытой скобкой мы ожидаем не оператор, а что-то другое (исключение префиксный оператор. №8).
16) Перейдём на следующий символ.
17) Запустим цикл заново.
18) Попался символ закрывающей скобки. Уменьшим счётчик скобок.
19) После закрывающейся скобки мы ожидаем увидеть оператор.
20) Кажется мы наткнулись на начало именни переменной. А может быть мы уже прочли одну переменную, или закрыли скобку? Может мы ждём оператор? А если нет? Дальше читаем переменную, и ждём что за переменной последует оператор, или закрывающая скобка (она же не проверяет ожидание оператора).
21) А вот и начался оператор. Если сдесь ожидалось что-нибудь другое, а не оператор, например оператор уже был, то это ошибка. Дальше ожидаем не оператор.
22) Пробел.
23) Если мы дошли сюда, то значит в выражении есть символ на который не начинаются переменные и операторы, и это точно не скобки и не пробел. То есть это ошибка! Неизвестный символ.
24) Мы вышли из цикла здоровыми и невредимыми. Но все ли скобки закрыты (открыты)?
25) Функция проверки выражения.
26) Маленькая хитрость.
27) Создаём экземпляр класса.
28) Метод проверки запускаем в блоке try except. Как так, ты ещё не прочитал про исключения? Просил же первой строчкой. Если во время выполнения программы возникнет исключение (именно наше), то мы прыгнем сразу за блок except. И соответственно не увидим слов “Всё хорошо”. “print e” выведет текст который мы писали генерируя исключение.
29) Ну чтож. Поехали :)
Почему именно так? Потому что добавив всего пару методов можно построить собственный интерпретатор. Вместо имён переменных можно подставлять значения. В общем вплоть до вычисления выражения.
Надеюсь это было полезно. Но!
Но в контексте поставленной задачи, код Ed'a намного лучше. Вот сам сейчас пытаюсь разобрать эту регулярку. В последний раз юзал регулярные выражения в 2006 на PHP. :)