kelvint 2004/03/15 19:17:18 Modified: contributions/javascript/queryValidator luceneQueryValidator.js Added: contributions/javascript/queryValidator testQueryValidator.html Log: Extracted validation methods so they can be tested via jsunit. Handles query escaping via a workaround. Yay! Checks for empty quotes. Simplified many REs. Allows the '=' sign. Revision Changes Path 1.7 +219 -102 jakarta-lucene-sandbox/contributions/javascript/queryValidator/luceneQueryValidator.js Index: luceneQueryValidator.js =================================================================== RCS file: /home/cvs/jakarta-lucene-sandbox/contributions/javascript/queryValidator/luceneQueryValidator.js,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- luceneQueryValidator.js 13 Jan 2004 07:01:32 -0000 1.6 +++ luceneQueryValidator.js 16 Mar 2004 03:17:17 -0000 1.7 @@ -1,4 +1,4 @@ -// Author: Kelvin Tan ([EMAIL PROTECTED]) +// Author: Kelvin Tan (kelvint at apache.org) // JavaScript Lucene Query Validator // Version: $Id$ // Tested: IE 6.0.2800 and Mozilla Firebird 0.7 @@ -17,6 +17,7 @@ wildcardCaseInsensitive = bool; } +// Should the user be prompted with an alert box if validation fails? var alertUser = true; function setAlertUser(bool) @@ -28,128 +29,52 @@ // @param Form field that contains the query function doCheckLuceneQuery(queryField) { - var query = queryField.value; + return doCheckLuceneQueryValue(queryField.value) +} + +// validates a lucene query. +// @param query string +function doCheckLuceneQueryValue(query) +{ if(query != null && query.length > 0) { + query = removeEscapes(query); + // check for allowed characters - var matches = query.match(/[^a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED] ]/); - if(matches != null && matches.length > 0) - { - if(alertUser) alert("Invalid search query! The allowed characters are a-z A-Z 0-9. _ + - : () \" & * ? | ! {} [ ] ^ ~ \\ @ #. Please try again.") - return false; - } + if(!checkAllowedCharacters(query)) return false; - // check wildcards are used properly - matches = query.match(/^[\*]*$|[\s]\*|^\*[^\s]/); - if(matches != null && matches.length > 0) - { - if(alertUser) alert("Invalid search query! The wildcard (*) character must be preceded by at least one alphabet or number. Please try again.") - return false; - } + // check * is used properly + if(!checkAsterisk(query)) return false; // check for && usage - // NB: doesn't handle term1 && term2 && term3 in Firebird 0.7 - matches = query.match(/[&]{2}/); - if(matches != null && matches.length > 0) - { - matches = query.match(/^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]( && )?[a-zA-Z0-9_+\-:.()\"*?|[EMAIL PROTECTED] ]*)+$/); // note missing & in pattern - if(matches == null) - { - if(alertUser) alert("Invalid search query! Queries containing the special characters && must be in the form: term1 && term2. Please try again.") - return false; - } - } + if(!checkAmpersands(query)) return false; // check ^ is used properly - matches = query.match(/^[^\^]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](\^[\d]+)?[ ]*)+$/); // note missing ^ in pattern - if(matches == null) - { - if(alertUser) alert("Invalid search query! The caret (^) character must be preceded by alphanumeric characters and followed by numbers. Please try again.") - return false; - } + if(!checkCaret(query)) return false; // check ~ is used properly - matches = query.match(/^[^~]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](~[\d.]+)?[ ]*)+$/); // note missing ~in pattern - if(matches == null) - { - if(alertUser) alert("Invalid search query! The tilde (~) character must be preceded by alphanumeric characters and followed by numbers. Please try again.") - return false; - } + if(!checkSquiggle(query)) return false; // check ! is used properly - // NB: doesn't handle term1 ! term2 ! term3 - matches = query.match(/^[^!]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]( ! )?[a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED] ]*)+$/); - if(matches == null || matches.length == 0) - { - if(alertUser) alert("Invalid search query! Queries containing the special character ! must be in the form: term1 ! term2. Please try again.") - return false; - } + if(!checkExclamationMark(query)) return false; // check question marks are used properly - matches = query.match(/^(\?)|([^a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED])/); - if(matches != null && matches.length > 0) - { - if(alertUser) alert("Invalid search query! The question mark (?) character must be preceded by at least one alphabet or number. Please try again.") - return false; - } + if(!checkQuestionMark(query)) return false; // check parentheses are used properly - matches = query.match(/^[^()]*$|^(\([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]))*$/); - if(matches == null || matches.length == 0) - { - if(alertUser) alert("Invalid search query! Parentheses must be closed and contain at least one alphabet or number. Please try again.") - return false; - } - + if(!checkParentheses(query)) return false; + // check '+' and '-' are used properly - matches = query.match(/^[^\n+\-]*$|^([+-]?[a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED] ]?)+$/); - if(matches == null || matches.length == 0) - { - if(alertUser) alert("Invalid search query! '+' and '-' modifiers must be followed by at least one alphabet or number. Please try again.") - return false; - } + if(!checkPlusMinus(query)) return false; // check AND, OR and NOT are used properly - matches = query.match(/AND|OR|NOT/); - if(matches != null && matches.length > 0) - { - // I've no idea why the code below doesn't work since it's identical to the exclamation mark and && RE - //matches = query.match(/^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](?: AND )?(?: OR )?(?: NOT )?[a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED] ]*)+$/); - - // we'll notify the user that this query is not validated and an error may result - if(alertUser) - { - return confirm("Validation for queries containing AND/OR/NOT is currently not supported. If your query is not well-formed, an error may result."); - } - /* - if(matches == null || matches.length == 0) - { - if(alertUser) alert("Invalid search query! Queries containing AND/OR/NOT must be in the form: term1 AND|OR|NOT term2 Please try again.") - return false; - } - */ - } - + if(!checkANDORNOT(query)) return false; // check that quote marks are closed - matches = query.match(/\"/g); - if(matches != null && matches.length > 0) - { - var number = matches.length; - if((number % 2) > 0) - { - if(alertUser) alert("Invalid search query! Please close all quote (\") marks."); - return false; - } - } + if(!checkQuotes(query)) return false; // check ':' is used properly - matches = query.match(/^[^:]*$|^([a-zA-Z0-9_+\-.()\"*?&|[EMAIL PROTECTED](:[a-zA-Z0-9_+\-.()\"*?&|[EMAIL PROTECTED])?[ ]*)+$/); // note missing : in pattern - if(matches == null || matches.length == 0) - { - if(alertUser) alert("Invalid search query! Field declarations (:) must be preceded by at least one alphabet or number and followed by at least one alphabet or number. Please try again.") - return false; - } + if(!checkColon(query)) return false; if(wildcardCaseInsensitive) { @@ -166,7 +91,199 @@ } } } - return true; } } + +// remove the escape character and the character immediately following it +function removeEscapes(query) +{ + return query.replace(/\\./g, ""); +} + +function checkAllowedCharacters(query) +{ + matches = query.match(/[^a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]'= ]/); + if(matches != null && matches.length > 0) + { + if(alertUser) alert("Invalid search query! The allowed characters are a-z A-Z 0-9. _ + - : () \" & * ? | ! {} [ ] ^ ~ \\ @ = # % $ '. Please try again.") + return false; + } + return true; +} + +function checkAsterisk(query) +{ + matches = query.match(/^[\*]*$|[\s]\*|^\*[^\s]/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! The wildcard (*) character must be preceded by at least one alphabet or number. Please try again.") + return false; + } + return true; +} + +function checkAmpersands(query) +{ + // NB: doesn't handle term1 && term2 && term3 in Firebird 0.7 + matches = query.match(/[&]{2}/); + if(matches != null && matches.length > 0) + { + matches = query.match(/^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]'=]+( && )?[a-zA-Z0-9_+\-:.()\"*?|[EMAIL PROTECTED]'=]+[ ]*)+$/); // note missing & in pattern + if(matches == null) + { + if(alertUser) alert("Invalid search query! Queries containing the special characters && must be in the form: term1 && term2. Please try again.") + return false; + } + } + return true; +} + +function checkCaret(query) +{ + //matches = query.match(/^[^\^]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](\^[\d]+)?[ ]*)+$/); // note missing ^ in pattern + matches = query.match(/[^\\]\^([^\s]*[^0-9.]+)|[^\\]\^$/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! The caret (^) character must be preceded by alphanumeric characters and followed by numbers. Please try again.") + return false; + } + return true; +} + +function checkSquiggle(query) +{ + //matches = query.match(/^[^~]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](~[\d.]+|[^\\]\\~)?[ ]*)+$/); // note missing ~ in pattern + matches = query.match(/[^\\]~[^\s]*[^0-9\s]+/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! The tilde (~) character must be preceded by alphanumeric characters and followed by numbers. Please try again.") + return false; + } + return true; +} + +function checkExclamationMark(query) +{ + // NB: doesn't handle term1 ! term2 ! term3 + matches = query.match(/^[^!]*$|^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]'=]+( ! )?[a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]'=]+[ ]*)+$/); + if(matches == null || matches.length == 0) + { + if(alertUser) alert("Invalid search query! Queries containing the special character ! must be in the form: term1 ! term2. Please try again.") + return false; + } + return true; +} + +function checkQuestionMark(query) +{ + matches = query.match(/^(\?)|([^a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED]'=]\?+)/); + if(matches != null && matches.length > 0) + { + if(alertUser) alert("Invalid search query! The question mark (?) character must be preceded by at least one alphabet or number. Please try again.") + return false; + } + return true; +} + +function checkParentheses(query) +{ + var hasLeft = false; + var hasRight = false; + matchLeft = query.match(/[(]/g); + if(matchLeft != null) hasLeft = true + matchRight = query.match(/[)]/g); + if(matchRight != null) hasRight = true; + + if(hasLeft || hasRight) + { + if(hasLeft && !hasRight || hasRight && !hasLeft) + { + if(alertUser) alert("Invalid search query! Parentheses must be closed. Please try again.") + return false; + } + else + { + var number = matchLeft.length + matchRight.length; + if((number % 2) > 0 || matchLeft.length != matchRight.length) + { + if(alertUser) alert("Invalid search query! Parentheses must be closed. Please try again.") + return false; + } + } + matches = query.match(/\(\)/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! Parentheses must contain at least one character. Please try again.") + return false; + } + } + return true; +} + +function checkPlusMinus(query) +{ + matches = query.match(/^[^\n+\-]*$|^([+-]?[a-zA-Z0-9_:.()\"*?&|[EMAIL PROTECTED]'=]+[ ]?)+$/); + if(matches == null || matches.length == 0) + { + if(alertUser) alert("Invalid search query! '+' and '-' modifiers must be followed by at least one alphabet or number. Please try again.") + return false; + } + return true; +} + +function checkANDORNOT(query) +{ + matches = query.match(/AND|OR|NOT/); + if(matches != null && matches.length > 0) + { + // I've no idea why the code below doesn't work since it's identical to the exclamation mark and && RE + //matches = query.match(/^([a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED](?: AND )?(?: OR )?(?: NOT )?[a-zA-Z0-9_+\-:.()\"*?&|[EMAIL PROTECTED] ]*)+$/); + + // we'll notify the user that this query is not validated and an error may result + if(alertUser) + { + return confirm("Validation for queries containing AND/OR/NOT is currently not supported. If your query is not well-formed, an error may result."); + } + /* + if(matches == null || matches.length == 0) + { + if(alertUser) alert("Invalid search query! Queries containing AND/OR/NOT must be in the form: term1 AND|OR|NOT term2 Please try again.") + return false; + } + */ + } + return true; +} + +function checkQuotes(query) +{ + matches = query.match(/\"/g); + if(matches != null && matches.length > 0) + { + var number = matches.length; + if((number % 2) > 0) + { + if(alertUser) alert("Invalid search query! Please close all quote (\") marks."); + return false; + } + matches = query.match(/""/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! Quotes must contain at least one character. Please try again.") + return false; + } + } + return true; +} + +function checkColon(query) +{ + matches = query.match(/[^\\\s]:[\s]|[^\\\s]:$|[\s][^\\]?:|^[^\\\s]?:/); + if(matches != null) + { + if(alertUser) alert("Invalid search query! Field declarations (:) must be preceded by at least one alphabet or number and followed by at least one alphabet or number. Please try again.") + return false; + } + return true; +} \ No newline at end of file 1.1 jakarta-lucene-sandbox/contributions/javascript/queryValidator/testQueryValidator.html Index: testQueryValidator.html =================================================================== <html> <head> <script language="JavaScript" src="f:/jsunit/app/jsUnitCore.js"></script> <script language="JavaScript" src="luceneQueryValidator.js"></script> </head> <body> <script> setAlertUser(false); // additions to jsUnit function assertTrue(comment, value) { return assertEquals(comment, true, value); } function assertFalse(comment, value) { return assertEquals(comment, false, value); } function testRemoveEscapes() { var query = "\\* foo \\haha"; assertEquals(query, " foo aha", removeEscapes(query)); query = "\\\\foo"; assertEquals(query, "foo", removeEscapes(query)); query = "foo\\\""; assertEquals(query, "foo", removeEscapes(query)); } function testCheckAllowedCharacters() { fail(""); } function testCheckAsterisk() { var query = "foo bar is ok"; assertTrue(query, checkAsterisk(query)); query = "foo bar12* is ok*"; assertTrue(query, checkAsterisk(query)); query = "foo bar12*sdsd"; assertTrue(query, checkAsterisk(query)); query = "foo bar12*sd**sd"; assertTrue(query, checkAsterisk(query)); query = "*bar12"; assertFalse(query, checkAsterisk(query)); query = "*ba12r*"; assertFalse(query, checkAsterisk(query)); query = "bar* *bar"; assertFalse(query, checkAsterisk(query)); // test with a space in front query = " *bar"; assertFalse(query, checkAsterisk(query)); // test the escaped case query = "bar* \\*bar"; assertTrue(query, checkAsterisk(query)); // try including other special characters query = "foo:bar*ba?r"; assertTrue(query, checkAsterisk(query)); query = "foo:(ba*ba?r zoo \"zaa zoo\")"; assertTrue(query, checkAsterisk(query)); } function testCheckAmpersands() { var query = "foo bar is ok"; assertTrue(query, checkAmpersands(query)); query = "foo & bar"; assertTrue(query, checkAmpersands(query)); query = "foo & bar& metoo &"; assertTrue(query, checkAmpersands(query)); query = "foo && bar12isok"; assertTrue(query, checkAmpersands(query)); query = "bar12 &&"; assertFalse(query, checkAmpersands(query)); query = "bar12 && bar12 &&"; assertFalse(query, checkAmpersands(query)); query = "bar12 && "; assertFalse(query, checkAmpersands(query)); } function testCheckCaret() { var query = "foo bar is ok"; assertTrue(query, checkCaret(query)); var query = "foo bar12isok^1.0"; assertTrue(query, checkCaret(query)); query = "\"jakarta apache\"^10"; assertTrue(query, checkCaret(query)); query = "bar12^"; assertFalse(query, checkCaret(query)); query = "bar12^10 bar12^"; assertFalse(query, checkCaret(query)); query = "bar12^ "; assertFalse(query, checkCaret(query)); query = "bar12^ me too"; assertFalse(query, checkCaret(query)); query = "bar12^foo"; assertFalse(query, checkCaret(query)); query = "bar12^1.foo"; assertFalse(query, checkCaret(query)); // test the escaped case query = "\\^"; assertTrue(query, checkCaret(query)); query = "bar\\^"; assertTrue(query, checkCaret(query)); // try including other special characters query = "bar*ba?r^1.0"; assertTrue(query, checkCaret(query)); } function testCheckSquiggle() { var query = "foo bar is ok"; assertTrue(query, checkSquiggle(query)); var query = "foo bar12isok~10"; assertTrue(query, checkSquiggle(query)); query = "\"jakarta apache\"~10"; assertTrue(query, checkSquiggle(query)); query = "bar12~"; assertTrue(query, checkSquiggle(query)); query = "bar12~10 bar12~"; assertTrue(query, checkSquiggle(query)); query = "bar12~ "; assertTrue(query, checkSquiggle(query)); query = "bar12~foo"; assertFalse(query, checkSquiggle(query)); query = "bar12~1f"; assertFalse(query, checkSquiggle(query)) // test the escaped case query = "\\~"; assertTrue(query, checkSquiggle(query)); query = "bar\\~"; assertTrue(query, checkSquiggle(query)); // try including other special characters query = "bar*ba?r~10"; assertTrue(query, checkSquiggle(query)); // FIXME: how about floating point proximity searches, e.g. foo~2.5 } function testCheckExclamationMark() { var query = "foo bar is ok"; assertTrue(query, checkExclamationMark(query)); query = "foo ! bar"; assertTrue(query, checkExclamationMark(query)); query = "\"foo\" ! \"bar\""; assertTrue(query, checkExclamationMark(query)); query = "foo!"; assertTrue(query, checkExclamationMark(query)); query = "! bar"; assertFalse(query, checkExclamationMark(query)); query = "foo !"; assertFalse(query, checkExclamationMark(query)); query = "foo ! "; assertFalse(query, checkExclamationMark(query)); // test escaped case query = "foo \\!"; assertTrue(query, checkExclamationMark(query)); query = "foo ! bar \\!"; assertTrue(query, checkExclamationMark(query)); query = "foo ! bar ! car"; assertTrue(query, checkExclamationMark(query)); query = "foo ! bar !"; assertFalse(query, checkExclamationMark(query)); query = "foo ! bar ! "; assertFalse(query, checkExclamationMark(query)); // try more complex queries query = "(foo bar) ! (car:dog*)"; assertTrue(query, checkExclamationMark(query)); } function testCheckQuestionMark() { var query = "foo bar is ok"; assertTrue(query, checkQuestionMark(query)); query = "foo bar12? is ok?"; assertTrue(query, checkQuestionMark(query)); query = "foo bar12?sdsd"; assertTrue(query, checkQuestionMark(query)); query = "foo bar12?sd??sd"; assertTrue(query, checkQuestionMark(query)); query = "?bar12"; assertFalse(query, checkQuestionMark(query)); query = "?ba12r?"; assertFalse(query, checkQuestionMark(query)); query = "bar? ?bar"; assertFalse(query, checkQuestionMark(query)); // test with a space in front query = " ?bar"; assertFalse(query, checkQuestionMark(query)); // test the escaped case query = "bar? \\?bar"; assertTrue(query, checkQuestionMark(query)); // try including other special characters query = "foo:bar*ba?r"; assertTrue(query, checkQuestionMark(query)); query = "foo:(ba*ba?r zoo \"zaa zoo\")"; assertTrue(query, checkQuestionMark(query)); } function testCheckParentheses() { var query = "foo bar is ok"; assertTrue(query, checkParentheses(query)); query = "(foobar12:isok)"; assertTrue(query, checkParentheses(query)); query = "(foobar12):(sdsd* me too)"; assertTrue(query, checkParentheses(query)); query = "(bar12"; assertFalse(query, checkParentheses(query)); query = "ba12r)"; assertFalse(query, checkParentheses(query)); query = "()"; assertFalse(query, checkParentheses(query)); query = "))"; assertFalse(query, checkParentheses(query)); query = "(foo bar) (bar"; assertFalse(query, checkParentheses(query)); query = "(foo bar) bar) me too"; assertFalse(query, checkParentheses(query)); // test with a space in front query = " (bar"; assertFalse(query, checkParentheses(query)); // test the escaped case query = "foo\\)"; assertTrue(query, doCheckLuceneQueryValue(query)); query = "foo\\) (foo bar)"; assertTrue(query, doCheckLuceneQueryValue(query)); // try including other special characters query = "-(foo bar*ba?r)"; assertTrue(query, checkParentheses(query)); query = "+foo:(ba*ba?r zoo -(zaa zoo))"; assertTrue(query, checkParentheses(query)); query = "((bar12"; assertFalse(query, checkParentheses(query)); query = "((bar12)"; assertFalse(query, checkParentheses(query)); } function testCheckPlusMinus() { var query = "foo bar is ok"; assertTrue(query, checkPlusMinus(query)); query = "+bar -foo"; assertTrue(query, checkPlusMinus(query)); // is this allowed? query = "baa+foo +foo-bar"; assertTrue(query, checkPlusMinus(query)); query = "baa+"; assertFalse(query, checkPlusMinus(query)); query = "++baa"; assertFalse(query, checkPlusMinus(query)); query = "+"; assertFalse(query, checkPlusMinus(query)); query = "-"; assertFalse(query, checkPlusMinus(query)); // test the escaped case query = "foo\\+"; assertTrue(query, doCheckLuceneQueryValue(query)); // try including other special characters query = "-(foo bar*ba?r)"; assertTrue(query, checkParentheses(query)); query = "+foo:(ba*ba?r zoo -(zaa zoo))"; assertTrue(query, checkParentheses(query)); } function testCheckANDORNOT() { fail(""); } function testCheckQuotes() { var query = "foo bar is ok"; assertTrue(query, checkQuotes(query)); query = "\"foobar12:isok\""; assertTrue(query, checkQuotes(query)); query = "\"(foobar12)\":(sdsd* me too)"; assertTrue(query, checkQuotes(query)); query = "\"bar12"; assertFalse(query, checkQuotes(query)); query = "\"\""; assertFalse(query, checkQuotes(query)); query = "ba12r\""; assertFalse(query, checkQuotes(query)); query = "\"foo bar\" \"bar"; assertFalse(query, checkQuotes(query)); query = "\"foo bar\" bar\" me too"; assertFalse(query, checkQuotes(query)); // test with a space in front query = " \"bar"; assertFalse(query, checkQuotes(query)); // test the escaped case query = "foo\\\""; assertTrue(query, doCheckLuceneQueryValue(query)); query = "foo\\\" \"foo bar\""; assertTrue(query, doCheckLuceneQueryValue(query)); // try including other special characters query = "\"foo bar*ba?r\""; assertTrue(query, checkQuotes(query)); query = "foo:(ba*ba?r zoo \"zaa zoo\")"; assertTrue(query, checkQuotes(query)); query = "\\\"\\\"bar12\\\""; assertTrue(query, doCheckLuceneQueryValue(query)); query = "\\\"\\\"bar12\\\"\\\""; assertTrue(query, doCheckLuceneQueryValue(query)); } function testCheckColon() { var query = "foo bar is ok"; assertTrue(query, checkColon(query)); query = "foobar12:isok"; assertTrue(query, checkColon(query)); query = "(foobar12):(sdsd* me too)"; assertTrue(query, checkColon(query)); query = "bar12:"; assertFalse(query, checkColon(query)); query = ":ba12r"; assertFalse(query, checkColon(query)); query = "foo:bar :bar"; assertFalse(query, checkColon(query)); query = "foo:bar bar: me too"; assertFalse(query, checkColon(query)); // test with a space in front query = " :bar"; assertFalse(query, checkColon(query)); // test the escaped case query = "foo\\:"; assertTrue(query, checkColon(query)); query = "foo\\: foo:bar"; assertTrue(query, checkColon(query)); // try including other special characters query = "foo:bar*ba?r"; assertTrue(query, checkColon(query)); query = "foo:(ba*ba?r zoo \"zaa zoo\")"; assertTrue(query, checkColon(query)); } </script> </body> </html>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]