diff src/goodjava/queryparser/SaneQueryParser.java @ 1422:e48290f3d9fb

better quoting
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 17 Nov 2019 16:28:51 -0700
parents 27efb1fcbcb5
children
line wrap: on
line diff
--- a/src/goodjava/queryparser/SaneQueryParser.java	Sat Oct 26 22:28:46 2019 -0600
+++ b/src/goodjava/queryparser/SaneQueryParser.java	Sun Nov 17 16:28:51 2019 -0700
@@ -19,10 +19,15 @@
 		return new SaneQueryParser(fieldParser,query).parseQuery();
 	}
 
-	private static Pattern specialChar = Pattern.compile("[ \\t\\r\\n\":\\[\\]{}^+\\-(),?*\\\\]");
-
-	public static String literal(String s) {
-		return specialChar.matcher(s).replaceAll("\\\\$0");
+	public static String quote(String s) {
+		s = s.replace("\\","\\\\");
+		s = s.replace("\b","\\b");
+		s = s.replace("\f","\\f");
+		s = s.replace("\n","\\n");
+		s = s.replace("\r","\\r");
+		s = s.replace("\t","\\t");
+		s = s.replace("\"","\\\"");
+		return "\""+s+"\"";
 	}
 
 	public static Sort parseSort(FieldParser fieldParser,String sort) throws ParseException {
@@ -167,20 +172,9 @@
 
 	private String SimpleTerm(String exclude) throws ParseException {
 		parser.begin();
-		String match;
-		if( parser.match('"') ) {
-			int start = parser.currentIndex() - 1;
-			while( !parser.match('"') ) {
-				if( parser.endOfInput() )
-					throw exception("unclosed quotes");
-				parser.anyChar();
-				checkEscape();
-			}
-			match = parser.textFrom(start);
-			Spaces();
-		} else {
+		String match = Quoted();
+		if( match==null )
 			match = Unquoted(exclude);
-		}
 		if( match.length() == 0 )
 			throw exception("invalid input");
 		return parser.success(match);
@@ -204,6 +198,67 @@
 		return parser.success(match);
 	}
 
+	private String Quoted() throws ParseException {
+		parser.begin();
+		if( !parser.match('"') )
+			return parser.failure(null);
+		StringBuilder sb = new StringBuilder();
+		while( parser.anyChar() ) {
+			char c = parser.lastChar();
+			switch(c) {
+			case '"':
+				return parser.success(sb.toString());
+			case '\\':
+				if( parser.anyChar() ) {
+					c = parser.lastChar();
+					switch(c) {
+					case '"':
+					case '\\':
+						sb.append(c);
+						continue;
+					case 'b':
+						sb.append('\b');
+						continue;
+					case 'f':
+						sb.append('\f');
+						continue;
+					case 'n':
+						sb.append('\n');
+						continue;
+					case 'r':
+						sb.append('\r');
+						continue;
+					case 't':
+						sb.append('\t');
+						continue;
+					case 'u':
+						int n = 0;
+						for( int i=0; i<4; i++ ) {
+							int d;
+							if( parser.inCharRange('0','9') ) {
+								d = parser.lastChar() - '0';
+							} else if( parser.inCharRange('a','f') ) {
+								d = parser.lastChar() - 'a' + 10;
+							} else if( parser.inCharRange('A','F') ) {
+								d = parser.lastChar() - 'A' + 10;
+							} else {
+								throw exception("invalid hex digit");
+							}
+							n = 16*n + d;
+						}
+						sb.append((char)n);
+						continue;
+					}
+				}
+				throw exception("invalid escape char");
+			default:
+				sb.append(c);
+			}
+		}
+		parser.failure();
+		throw exception("unclosed string");
+	}
+
 	private String Unquoted(String exclude) throws ParseException {
 		int start = parser.begin();
 		while( parser.noneOf(exclude) ) {