blob: 42c61f563313b4d190fa8a4daa22b4645fba8689 [file] [log] [blame]
using J2N.Text;
using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
using Lucene.Net.QueryParsers.Flexible.Core.Processors;
using Lucene.Net.QueryParsers.Flexible.Core.Util;
using Lucene.Net.QueryParsers.Flexible.Standard.Nodes;
using System.Collections.Generic;
namespace Lucene.Net.QueryParsers.Flexible.Standard.Processors
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <summary>
/// The <see cref="Parser.StandardSyntaxParser"/> creates <see cref="PrefixWildcardQueryNode"/> nodes which
/// have values containing the prefixed wildcard. However, Lucene
/// <see cref="Search.PrefixQuery"/> cannot contain the prefixed wildcard. So, this processor
/// basically removed the prefixed wildcard from the
/// <see cref="PrefixWildcardQueryNode"/> value.
/// </summary>
/// <seealso cref="Search.PrefixQuery"/>
/// <seealso cref="PrefixWildcardQueryNode"/>
public class WildcardQueryNodeProcessor : QueryNodeProcessor
{
public WildcardQueryNodeProcessor()
{
// empty constructor
}
protected override IQueryNode PostProcessNode(IQueryNode node)
{
// the old Lucene Parser ignores FuzzyQueryNode that are also PrefixWildcardQueryNode or WildcardQueryNode
// we do the same here, also ignore empty terms
if (node is FieldQueryNode || node is FuzzyQueryNode)
{
FieldQueryNode fqn = (FieldQueryNode)node;
string text = fqn.Text.ToString();
// do not process wildcards for TermRangeQueryNode children and
// QuotedFieldQueryNode to reproduce the old parser behavior
if (fqn.Parent is TermRangeQueryNode
|| fqn is QuotedFieldQueryNode
|| text.Length <= 0)
{
// Ignore empty terms
return node;
}
// Code below simulates the old lucene parser behavior for wildcards
if (IsPrefixWildcard(text))
{
PrefixWildcardQueryNode prefixWildcardQN = new PrefixWildcardQueryNode(fqn);
return prefixWildcardQN;
}
else if (IsWildcard(text))
{
WildcardQueryNode wildcardQN = new WildcardQueryNode(fqn);
return wildcardQN;
}
}
return node;
}
private static bool IsWildcard(string text) // LUCENENET: CA1822: Mark members as static
{
if (text == null || text.Length <= 0) return false;
// If a un-escaped '*' or '?' if found return true
// start at the end since it's more common to put wildcards at the end
for (int i = text.Length - 1; i >= 0; i--)
{
if ((text[i] == '*' || text[i] == '?') && !UnescapedCharSequence.WasEscaped(new StringCharSequence(text), i))
{
return true;
}
}
return false;
}
private bool IsPrefixWildcard(string text)
{
if (text == null || text.Length <= 0 || !IsWildcard(text)) return false;
// Validate last character is a '*' and was not escaped
// If single '*' is is a wildcard not prefix to simulate old queryparser
if (text[text.Length - 1] != '*') return false;
if (UnescapedCharSequence.WasEscaped(new StringCharSequence(text), text.Length - 1)) return false;
if (text.Length == 1) return false;
// Only make a prefix if there is only one single star at the end and no '?' or '*' characters
// If single wildcard return false to mimic old queryparser
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '?') return false;
if (text[i] == '*' && !UnescapedCharSequence.WasEscaped(new StringCharSequence(text), i))
{
if (i == text.Length - 1)
return true;
else
return false;
}
}
return false;
}
protected override IQueryNode PreProcessNode(IQueryNode node)
{
return node;
}
protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
{
return children;
}
}
}