queryparser.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. # Created: 28.04.13
  2. # Copyright (C) 2013, Manfred Moitzi
  3. # License: MIT-License
  4. """
  5. EntityQueryParser implemented with the pyparsing module created by Paul T. McGuire.
  6. QueryString := EntityQuery ("[" AttribQuery "]" "i"?)*
  7. The QueryString consist of two queries, first the required entity query and the second optional attribute query,
  8. enclosed in square brackets an optional appended "i" indicates ignore case for string queries.
  9. 1. EntityQuery (required)
  10. The EntityQuery is a whitespace separated list of names (DXF entity names) or the special name "*".
  11. 2. AttribQuery (optional)
  12. The AttribQuery is a boolean expression, supported boolean operators are:
  13. - '!' not: !term if true, if tern is false.
  14. - '&' and: term & term is true, if both terms are true.
  15. - '|' or: term | term is true, if one term is true.
  16. The query itself consist of a name a comparator and a value, like "color < 7".
  17. Supported comparators are:
  18. - '==': equal
  19. - '!=': not equal
  20. - '<': lower than
  21. - '<=': lower or equal than
  22. - '>': greater than
  23. - '>=': greater or equal than
  24. - '?': match a regular expression
  25. - '!?': does not match a regular expression
  26. Values can be integers, floats or strings, strings have to be quoted ("I am a string" or 'I am a string').
  27. examples:
  28. 'LINE CIRCLE[layer=="construction"]' => all LINE and CIRCLE entities on layer "construction"
  29. '*[!(layer=="construction" & color<7)]' => all entities except those on layer == "construction" and color < 7
  30. 'LINE[layer=="construction"]i' => all lines on layer named 'construction' with case insensitivity, "CoNsTrUcTiOn" is valid
  31. """
  32. from pyparsing import *
  33. LBRK = Suppress('[')
  34. RBRK = Suppress(']')
  35. number = Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
  36. number.addParseAction(lambda t: float(t[0])) # convert to float
  37. string_ = quotedString.addParseAction(lambda t: t[0][1:-1]) # remove quotes
  38. EntityName = Word(alphanums+'_')
  39. AttribName = EntityName
  40. Relation = oneOf(['==', '!=', '<', '<=', '>', '>=', '?', '!?'])
  41. AttribValue = string_ | number
  42. AttribQuery = Group(AttribName + Relation + AttribValue)
  43. EntityNames = Group(Literal('*') | OneOrMore(EntityName)).setResultsName('EntityQuery')
  44. InfixBoolQuery = infixNotation(AttribQuery, (
  45. ('!', 1, opAssoc.RIGHT),
  46. ('&', 2, opAssoc.LEFT),
  47. ('|', 2, opAssoc.LEFT),
  48. )).setResultsName('AttribQuery')
  49. AttribQueryOptions = Literal('i').setResultsName('AttribQueryOptions')
  50. EntityQueryParser = EntityNames + Optional(LBRK + InfixBoolQuery + RBRK + Optional(AttribQueryOptions))