Skip to content

Instantly share code, notes, and snippets.

@patarapolw
Created November 17, 2018 20:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patarapolw/4adb74fbf6f091f91f7a2bc04ef7aad2 to your computer and use it in GitHub Desktop.
Save patarapolw/4adb74fbf6f091f91f7a2bc04ef7aad2 to your computer and use it in GitHub Desktop.
import ast
import re
class SearchBox:
ast_table = {
ast.Eq: ':',
ast.Is: '=',
ast.Or: 'or',
ast.And: 'and',
ast.Gt: '>',
ast.GtE: '>=',
ast.Lt: '<',
ast.LtE: '<='
}
def __init__(self, q):
self.q = q
self._sub(' ', 'and')
self._sub('=', 'is')
self._sub(':', '==')
def parse(self):
"""
:return:
>>> SearchBox('').parse()
>>> SearchBox('a').parse()
'a'
>>> SearchBox('a:b').parse()
(':', ['a', 'b'])
>>> SearchBox('a:b c:d').parse()
('and', [(':', ['a', 'b']), (':', ['c', 'd'])])
>>> SearchBox('a:b:c').parse()
>>> SearchBox("a:'b c'").parse()
(':', ['a', 'b c'])
>>> SearchBox('a:"b c"').parse()
(':', ['a', 'b c'])
>>> SearchBox("'a b':c").parse()
(':', ['a b', 'c'])
>>> SearchBox("'a:b':c").parse()
(':', ['a:b', 'c'])
>>> SearchBox('tag:微信').parse()
(':', ['tag', '微信'])
"""
try:
return self._eval_node(ast.parse(self.q, mode='eval').body)
except SyntaxError:
return None
def _sub(self, src, dst):
match_obj = re.fullmatch(r'(?:({expr})({src}))+({expr})'.format(
expr='(?:\".*?\"|\'.*?\'|\S)+',
src=src
), self.q)
if match_obj:
new_q = list(match_obj.groups())
for i, fragment in enumerate(new_q):
if fragment[0] == src:
if not any(f[0] not in '"\'' and src in f for f in {new_q[i-1], new_q[i+1]}):
new_q[i] = ' ' + dst + ' '
self.q = ''.join(new_q)
def _eval_node(self, node):
if isinstance(node, ast.Name):
return node.id
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.Expr):
return self._eval_node(node.value)
elif isinstance(node, ast.BoolOp):
return self.ast_table[type(node.op)], [self._eval_node(v) for v in node.values]
elif isinstance(node, ast.Compare):
return self.ast_table[type(node.ops[0])], \
[self._eval_node(node.left), self._eval_node(node.comparators[0])]
else:
raise SyntaxError
if __name__ == '__main__':
for q in [
"'a b':c",
'a:"b c"',
"a:'b c'",
'a:b c:d'
]:
print(SearchBox(q).q)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment