/// <summary> /// Parses a query segment and converts it to an expression /// tree. /// </summary> /// <param name="query">Query segment to convert</param> /// <param name="defaultConjunction">Implicit conjunction type</param> /// <returns>Root node of expression tree</returns> private INode ParseNode(string query, ConjunctionTypes defaultConjunction) { TermForms termForm = TermForms.Inflectional; bool termExclude = false; ConjunctionTypes conjunction = defaultConjunction; bool resetState = true; INode root = null; INode node; string term; TextParser parser = new TextParser(query); while (!parser.EndOfText) { if (resetState) { // Reset modifiers termForm = TermForms.Inflectional; termExclude = false; conjunction = defaultConjunction; resetState = false; } parser.MovePastWhitespace(); if (!parser.EndOfText && Punctuation.IndexOf(parser.Peek()) < 0) { // Extract query term int start = parser.Position; parser.MoveAhead(); while (!parser.EndOfText && Punctuation.IndexOf(parser.Peek()) < 0 && !Char.IsWhiteSpace(parser.Peek())) { parser.MoveAhead(); } // Allow trailing wildcard if (parser.Peek() == '*') { parser.MoveAhead(); termForm = TermForms.Literal; } // Interpret token term = parser.Extract(start, parser.Position); if (String.Compare(term, "AND", true) == 0) { conjunction = ConjunctionTypes.And; } else if (String.Compare(term, "OR", true) == 0) { conjunction = ConjunctionTypes.Or; } else if (String.Compare(term, "NEAR", true) == 0) { conjunction = ConjunctionTypes.Near; } else if (String.Compare(term, "NOT", true) == 0) { termExclude = true; } else { root = AddNode(root, term, termForm, termExclude, conjunction); resetState = true; } continue; } else if (parser.Peek() == '"') { // Match next term exactly termForm = TermForms.Literal; // Extract quoted term term = ExtractQuote(parser); root = AddNode(root, term.Trim(), termForm, termExclude, conjunction); resetState = true; } else if (parser.Peek() == '(') { // Parse parentheses block term = ExtractBlock(parser, '(', ')'); node = ParseNode(term, defaultConjunction); root = AddNode(root, node, conjunction, true); resetState = true; } else if (parser.Peek() == '<') { // Parse angle brackets block term = ExtractBlock(parser, '<', '>'); node = ParseNode(term, ConjunctionTypes.Near); root = AddNode(root, node, conjunction); resetState = true; } else if (parser.Peek() == '-') { // Match when next term is not present termExclude = true; } else if (parser.Peek() == '+') { // Match next term exactly termForm = TermForms.Literal; } else if (parser.Peek() == '~') { // Match synonyms of next term termForm = TermForms.Thesaurus; } // Advance to next character parser.MoveAhead(); } return(root); }
/// <summary> /// Parses a query segment and converts it to an expression /// tree. /// </summary> /// <param name="query">Query segment to convert</param> /// <param name="defaultConjunction">Implicit conjunction type</param> /// <returns>Root node of expression tree</returns> private INode ParseNode(string query, ConjunctionTypes defaultConjunction) { TermForms termForm = TermForms.Inflectional; bool termExclude = false; ConjunctionTypes conjunction = defaultConjunction; bool resetState = true; INode root = null; INode node; string term; TextParser parser = new TextParser(query); while (!parser.EndOfText) { if (resetState) { // Reset modifiers termForm = TermForms.Inflectional; termExclude = false; conjunction = defaultConjunction; resetState = false; } parser.MovePastWhitespace(); if (!parser.EndOfText && Punctuation.IndexOf(parser.Peek()) < 0) { // Extract query term int start = parser.Position; parser.MoveAhead(); while (!parser.EndOfText && Punctuation.IndexOf(parser.Peek()) < 0 && !Char.IsWhiteSpace(parser.Peek())) parser.MoveAhead(); // Allow trailing wildcard if (parser.Peek() == '*') { parser.MoveAhead(); termForm = TermForms.Literal; } // Interpret token term = parser.Extract(start, parser.Position); if (String.Compare(term, "AND", true) == 0) conjunction = ConjunctionTypes.And; else if (String.Compare(term, "OR", true) == 0) conjunction = ConjunctionTypes.Or; else if (String.Compare(term, "NEAR", true) == 0) conjunction = ConjunctionTypes.Near; else if (String.Compare(term, "NOT", true) == 0) termExclude = true; else { root = AddNode(root, term, termForm, termExclude, conjunction); resetState = true; } continue; } else if (parser.Peek() == '"') { // Match next term exactly termForm = TermForms.Literal; // Extract quoted term term = ExtractQuote(parser); root = AddNode(root, term.Trim(), termForm, termExclude, conjunction); resetState = true; } else if (parser.Peek() == '(') { // Parse parentheses block term = ExtractBlock(parser, '(', ')'); node = ParseNode(term, defaultConjunction); root = AddNode(root, node, conjunction, true); resetState = true; } else if (parser.Peek() == '<') { // Parse angle brackets block term = ExtractBlock(parser, '<', '>'); node = ParseNode(term, ConjunctionTypes.Near); root = AddNode(root, node, conjunction); resetState = true; } else if (parser.Peek() == '-') { // Match when next term is not present termExclude = true; } else if (parser.Peek() == '+') { // Match next term exactly termForm = TermForms.Literal; } else if (parser.Peek() == '~') { // Match synonyms of next term termForm = TermForms.Thesaurus; } // Advance to next character parser.MoveAhead(); } return root; }