gallery.accords-library.com/server/szurubooru/search/parser.py

98 lines
3.4 KiB
Python
Raw Normal View History

import re
from szurubooru import errors
from szurubooru.search import criteria, tokens
def _create_criterion(original_value, value):
if '..' in value:
low, high = value.split('..', 1)
if not low and not high:
raise errors.SearchError('Empty ranged value')
return criteria.RangedCriterion(original_value, low, high)
if ',' in value:
return criteria.ArrayCriterion(
original_value, value.split(','))
return criteria.PlainCriterion(original_value, value)
def _parse_anonymous(value, negated):
criterion = _create_criterion(value, value)
return tokens.AnonymousToken(criterion, negated)
def _parse_named(key, value, negated):
original_value = value
if key.endswith('-min'):
key = key[:-4]
value += '..'
elif key.endswith('-max'):
key = key[:-4]
value = '..' + value
criterion = _create_criterion(original_value, value)
return tokens.NamedToken(key, criterion, negated)
def _parse_special(value, negated):
return tokens.SpecialToken(value, negated)
def _parse_sort(value, negated):
if value.count(',') == 0:
direction_str = None
elif value.count(',') == 1:
value, direction_str = value.split(',')
else:
raise errors.SearchError('Too many commas in sort style token.')
try:
direction = {
'asc': tokens.SortToken.SORT_ASC,
'desc': tokens.SortToken.SORT_DESC,
'': tokens.SortToken.SORT_DEFAULT,
None: tokens.SortToken.SORT_DEFAULT,
}[direction_str]
except KeyError:
raise errors.SearchError(
'Unknown search direction: %r.' % direction_str)
if negated:
direction = {
tokens.SortToken.SORT_ASC: tokens.SortToken.SORT_DESC,
tokens.SortToken.SORT_DESC: tokens.SortToken.SORT_ASC,
tokens.SortToken.SORT_DEFAULT: tokens.SortToken.SORT_NEGATED_DEFAULT,
tokens.SortToken.SORT_NEGATED_DEFAULT: tokens.SortToken.SORT_DEFAULT,
}[direction]
return tokens.SortToken(value, direction)
class SearchQuery():
def __init__(self):
self.anonymous_tokens = []
self.named_tokens = []
self.special_tokens = []
self.sort_tokens = []
def __hash__(self):
return hash((
tuple(self.anonymous_tokens),
tuple(self.named_tokens),
tuple(self.special_tokens),
tuple(self.sort_tokens)))
class Parser(object):
def parse(self, query_text):
query = SearchQuery()
for chunk in re.split(r'\s+', (query_text or '').lower()):
if not chunk:
continue
negated = False
while chunk[0] == '-':
chunk = chunk[1:]
negated = not negated
if ':' in chunk and chunk[0] != ':':
key, value = chunk.split(':', 2)
if key == 'sort':
query.sort_tokens.append(
_parse_sort(value, negated))
elif key == 'special':
query.special_tokens.append(
_parse_special(value, negated))
else:
query.named_tokens.append(
_parse_named(key, value, negated))
else:
query.anonymous_tokens.append(_parse_anonymous(chunk, negated))
return query