diff --git a/src/java/org/apache/lucene/queryParser/QueryParser.java b/src/java/org/apache/lucene/queryParser/QueryParser.java index 121dc7dd87c..a34e1cf8ac9 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParser.java +++ b/src/java/org/apache/lucene/queryParser/QueryParser.java @@ -429,6 +429,25 @@ public class QueryParser implements QueryParserConstants { return new String(caDest, 0, j); } + /** + * Returns a String where those characters that QueryParser + * expects to be escaped are escaped, i.e. preceded by a \. + */ + public static String escape(String s) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + // NOTE: keep this in sync with _ESCAPED_CHAR below! + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' + || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' + || c == '*' || c == '?') { + sb.append('\\'); + } + sb.append(c); + } + return sb.toString(); + } + public static void main(String[] args) throws Exception { QueryParser qp = new QueryParser("field", new org.apache.lucene.analysis.SimpleAnalyzer()); diff --git a/src/java/org/apache/lucene/queryParser/QueryParser.jj b/src/java/org/apache/lucene/queryParser/QueryParser.jj index 85ec5511338..44a2cf9b389 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParser.jj +++ b/src/java/org/apache/lucene/queryParser/QueryParser.jj @@ -452,6 +452,25 @@ public class QueryParser { return new String(caDest, 0, j); } + /** + * Returns a String where those characters that QueryParser + * expects to be escaped are escaped, i.e. preceded by a \. + */ + public static String escape(String s) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + // NOTE: keep this in sync with _ESCAPED_CHAR below! + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' + || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' + || c == '*' || c == '?') { + sb.append('\\'); + } + sb.append(c); + } + return sb.toString(); + } + public static void main(String[] args) throws Exception { QueryParser qp = new QueryParser("field", new org.apache.lucene.analysis.SimpleAnalyzer()); @@ -468,6 +487,7 @@ PARSER_END(QueryParser) <*> TOKEN : { <#_NUM_CHAR: ["0"-"9"] > +// NOTE: keep this in sync with escape(String) above! | <#_ESCAPED_CHAR: "\\" [ "\\", "+", "-", "!", "(", ")", ":", "^", "[", "]", "\"", "{", "}", "~", "*", "?" ] > | <#_TERM_START_CHAR: ( ~[ " ", "\t", "\n", "\r", "+", "-", "!", "(", ")", ":", "^", diff --git a/src/java/org/apache/lucene/search/TermQuery.java b/src/java/org/apache/lucene/search/TermQuery.java index 6ff9b2994a7..fa99867d84a 100644 --- a/src/java/org/apache/lucene/search/TermQuery.java +++ b/src/java/org/apache/lucene/search/TermQuery.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.queryParser.QueryParser; /** A Query that matches documents containing a term. This may be combined with other terms with a {@link BooleanQuery}. @@ -142,10 +143,10 @@ public class TermQuery extends Query { public String toString(String field) { StringBuffer buffer = new StringBuffer(); if (!term.field().equals(field)) { - buffer.append(term.field()); + buffer.append(QueryParser.escape(term.field())); buffer.append(":"); } - buffer.append(term.text()); + buffer.append(QueryParser.escape(term.text())); if (getBoost() != 1.0f) { buffer.append("^"); buffer.append(Float.toString(getBoost())); diff --git a/src/test/org/apache/lucene/queryParser/TestQueryParser.java b/src/test/org/apache/lucene/queryParser/TestQueryParser.java index c3519bb7ef7..ec0a763033e 100644 --- a/src/test/org/apache/lucene/queryParser/TestQueryParser.java +++ b/src/test/org/apache/lucene/queryParser/TestQueryParser.java @@ -317,7 +317,7 @@ public class TestQueryParser extends TestCase { public void testEscaped() throws Exception { Analyzer a = new WhitespaceAnalyzer(); - /* assertQueryEquals("\\[brackets", a, "\\[brackets"); + assertQueryEquals("\\[brackets", a, "\\[brackets"); assertQueryEquals("\\[brackets", null, "brackets"); assertQueryEquals("\\\\", a, "\\\\"); assertQueryEquals("\\+blah", a, "\\+blah"); @@ -337,29 +337,33 @@ public class TestQueryParser extends TestCase { assertQueryEquals("\\~blah", a, "\\~blah"); assertQueryEquals("\\*blah", a, "\\*blah"); assertQueryEquals("\\?blah", a, "\\?blah"); - assertQueryEquals("foo \\&& bar", a, "foo \\&& bar"); - assertQueryEquals("foo \\|| bar", a, "foo \\|| bar"); - assertQueryEquals("foo \\AND bar", a, "foo \\AND bar"); */ + + // TODO: what about these? + //assertQueryEquals("foo \\&\\& bar", a, "foo \\&\\& bar"); + //assertQueryEquals("foo \\|| bar", a, "foo \\|| bar"); + //assertQueryEquals("foo \\AND bar", a, "foo \\AND bar"); - assertQueryEquals("a\\-b:c",a,"a-b:c"); - assertQueryEquals("a\\+b:c",a,"a+b:c"); - assertQueryEquals("a\\:b:c",a,"a:b:c"); - assertQueryEquals("a\\\\b:c",a,"a\\b:c"); + assertQueryEquals("a\\-b:c",a,"a\\-b:c"); + assertQueryEquals("a\\+b:c",a,"a\\+b:c"); + assertQueryEquals("a\\:b:c",a,"a\\:b:c"); + assertQueryEquals("a\\\\b:c",a,"a\\\\b:c"); - assertQueryEquals("a:b\\-c",a,"a:b-c"); - assertQueryEquals("a:b\\+c",a,"a:b+c"); - assertQueryEquals("a:b\\:c",a,"a:b:c"); - assertQueryEquals("a:b\\\\c",a,"a:b\\c"); + assertQueryEquals("a:b\\-c",a,"a:b\\-c"); + assertQueryEquals("a:b\\+c",a,"a:b\\+c"); + assertQueryEquals("a:b\\:c",a,"a:b\\:c"); + assertQueryEquals("a:b\\\\c",a,"a:b\\\\c"); assertQueryEquals("a:b\\-c*",a,"a:b-c*"); assertQueryEquals("a:b\\+c*",a,"a:b+c*"); assertQueryEquals("a:b\\:c*",a,"a:b:c*"); + assertQueryEquals("a:b\\\\c*",a,"a:b\\c*"); assertQueryEquals("a:b\\-?c",a,"a:b-?c"); assertQueryEquals("a:b\\+?c",a,"a:b+?c"); assertQueryEquals("a:b\\:?c",a,"a:b:?c"); - assertQueryEquals("a:b\\\\?c",a,"a:b\\?c"); + + assertQueryEquals("a:b\\\\?c",a,"a:b\\\\\\?c"); assertQueryEquals("a:b\\-c~",a,"a:b-c~"); assertQueryEquals("a:b\\+c~",a,"a:b+c~");