1 class CompoundStatement:
2 def __init__(self, or_list, negneg=True):
4 self.neg = False if negneg else True
6 # return "<" + str(not self.neg) + ": OR'd " + str(self.or_list) + ">"
8 class LogicParserError(Exception):
11 def parseToCompoundStatement(string):
24 string = string.replace(meta_marker, "")
27 parentheses = parenthesis_in + parenthesis_out
31 if in_token and quote == "" and char in quotes + parentheses \
42 elif char in parentheses:
54 if char == quote or (quote == "" and char == space):
65 raise LogicParserError("Token not properly closed.")
70 def parenthesize(tokens):
73 def group_by_parentheses(i):
74 nonlocal open_parentheses
76 while i < len(tokens):
77 if tokens[i] == parenthesis_in:
79 i, token = group_by_parentheses(i + 1)
81 elif tokens[i] == parenthesis_out:
83 if open_parentheses < 0:
84 raise LogicParserError("Improper parentheses.")
85 return i + 1, compound
87 compound += [tokens[i]]
90 _, compounds = group_by_parentheses(0)
91 if open_parentheses > 0:
92 raise LogicParserError("Improper parentheses.")
95 def group_by_negation(tree):
98 if type(tree[i]) == str and tree[i] in not_words:
100 raise LogicParserError("Improper negation.")
102 tree[i] = [False, tree[i + 1]]
104 if type(tree[i][1]) == list:
105 group_by_negation(tree[i][1])
106 elif type(tree[i]) == list:
107 group_by_negation(tree[i])
110 def group_by_and(tree):
112 if type(tree[i]) == bool:
114 if type(tree[i]) == list:
115 group_by_and(tree[i])
116 if tree[i] in or_words + and_words:
117 raise LogicParserError("Improper AND/OR placement.")
118 while len(tree[i:]) > 1:
119 if tree[i + 1] not in or_words + and_words:
120 raise LogicParserError("Improper token grouping.")
121 elif len(tree[i:]) < 3 or \
122 tree[i + 2] in or_words + and_words:
123 raise LogicParserError("Improper AND/OR placement.")
124 if type(tree[i + 2]) == list:
125 group_by_and(tree[i + 2])
126 if tree[i + 1] in and_words:
127 # A AND B = NOT (NOT A OR NOT B)
128 tree[i] = [False, [[False, tree[i]], [False, tree[i + 2]]]]
134 def group_by_or(tree):
136 if type(tree[i]) == bool:
138 if type(tree[i]) == list:
140 if tree[i] in or_words:
141 raise LogicParserError("Improper OR placement.")
142 while len(tree[i:]) > 1:
143 if tree[i + 1] in or_words:
144 if type(tree[i + 2]) == list:
145 group_by_or(tree[i + 2])
146 tree[i + 1] = tree[i + 2]
149 if type(tree[i + 1]) == list:
150 group_by_or(tree[i + 1])
156 if type(tree[i]) == list:
157 tree[i] = flatten(tree[i])
159 if len(tree) == 1 and type(tree[0]) == list:
162 if len(tree) == 2 and tree[0] == False and type(tree[1]) == list \
163 and len(tree[1]) == 2 and tree[1][0] == False:
168 def strip_meta_marker(tree):
171 if type(tree[i]) == list:
172 strip_meta_marker(tree[i])
173 elif type(tree[i]) == str:
174 tree[i] = tree[i].replace(meta_marker, "")
177 def toCompoundStatement(compounds):
186 if type(tree[i]) == list:
187 or_group += [transform(tree[i])]
189 or_group += [tree[i]]
191 return CompoundStatement(or_group, negneg)
192 return transform(compounds)
194 tokens = tokenize(string)
195 compounds = parenthesize(tokens)
196 group_by_negation(compounds)
197 group_by_and(compounds)
198 group_by_or(compounds)
200 strip_meta_marker(compounds)
201 return toCompoundStatement(compounds)
203 def search(query, string_list):
205 def testStringMatchLogic(statement, compare_value):
206 if type(statement) == str:
207 statement_true = statement.lower() in compare_value.lower()
208 elif type(statement) == CompoundStatement:
210 if len(statement.or_list) > 1:
211 for i_statement in statement.or_list:
212 if testStringMatchLogic(i_statement, compare_value):
216 or_list_true = testStringMatchLogic(statement.or_list[0],
219 statement_true = not or_list_true
221 statement_true = or_list_true
222 return statement_true
225 statement = parseToCompoundStatement(query)
226 for i in range(len(string_list)):
227 if testStringMatchLogic(statement, string_list[i]):
228 results += [[i, string_list[i]]]
235 #"ist heut nicht ein schöner Tag?"
237 #query = "NOT (geht OR 'ö')"
238 #for line in search(query, lines):