package railo.runtime.search.lucene2.query; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import railo.commons.lang.ParserString; /** * The simple query is the default query type and is appropriate for the vast majority of searches. * When entering text on a search form, you perform a simple query by entering a word or comma-delimited strings, * with optional wildcard characters. * Verity treats each comma as a logical OR. If you omit the commas, Verity treats the expression as a phrase. */ public final class QueryParser { private static final String OR="or"; private static final String AND="and"; private static final String NOT="not"; private static final char QUOTER='"'; private static final String STAR = "*"; private List list=new ArrayList(); /** * parse given string query * @param criteria * @return matching Query */ public String parse(String criteria) { Op op = parseOp(criteria); if(op==null) return STAR; return op.toString(); } public Op parseOp(String criteria) { if(criteria.length()>0) { char first=criteria.charAt(0); // start with operator while(first=='*' || first=='~' || first=='?') { criteria=criteria.substring(1); if(criteria.length()==0) break; first=criteria.charAt(0); } } // make never foud query if quey is empty if(criteria.length()==0) { return null; } //StringBuffer str=new StringBuffer(); ParserString ps=new ParserString(criteria); Op op=null; while(!ps.isAfterLast()) { if(op==null)op=orOp(ps); else op=new Concator(op,orOp(ps)); } return op; } private Op orOp(ParserString ps) { Op op=andOp(ps); ps.removeSpace(); // OR while(ps.isValidIndex() && (ps.forwardIfCurrent(OR) || ps.forwardIfCurrent(','))) { ps.removeSpace(); if(ps.isAfterLast()) op=new Concator(op,new Literal("OR") ); else op=new Or(op,andOp(ps)); } return op; } private Op andOp(ParserString ps) { Op op = notOp(ps); ps.removeSpace(); // AND while(ps.isValidIndex() && ps.forwardIfCurrent(AND)) { ps.removeSpace(); if(ps.isAfterLast()) op=new Concator(op,new Literal("AND") ); else op=new And(op,notOp(ps)); } return op; } private Op notOp(ParserString ps) { Op op = spaceOp(ps); ps.removeSpace(); // NOT while(ps.isValidIndex() && ps.forwardIfCurrent(NOT)) { ps.removeSpace(); if(ps.isAfterLast()) op=new Concator(op,new Literal("NOT") ); else { Op r; op=new Not(op,r=clip(ps)); this.list.remove(r); } } return op; } private Op spaceOp(ParserString ps) { Op op = clip(ps); //ps.removeSpace(); // Concat while(ps.isValidIndex() && isSpace(ps.getCurrent()) && !(ps.isCurrentIgnoreSpace(OR) || ps.isCurrentIgnoreSpace(',') || ps.isCurrentIgnoreSpace(AND) || ps.isCurrentIgnoreSpace(NOT))) { ps.removeSpace(); op=new Concator(op,clip(ps)); } return op; } private Op clip(ParserString ps) { // () if(ps.isValidIndex() && ps.forwardIfCurrent('(')) { Op op=orOp(ps); ps.removeSpace(); ps.forwardIfCurrent(')'); ps.removeSpace(); return op; } return literal(ps); } private Op literal(ParserString ps) { ps.removeSpace(); if(ps.isCurrent(QUOTER)) return quotedLiteral(ps); return notQuotedLiteral(ps); } private Op quotedLiteral(ParserString ps) { StringBuffer str=new StringBuffer(); ps.next(); char c; while(!ps.isAfterLast()) { c=ps.getCurrent(); if(c==QUOTER) { ps.next(); if(ps.isCurrent(QUOTER)) str.append(QUOTER); else break; } else { str.append(c); } ps.next(); } return register(new Literal(str.toString())); } private Op notQuotedLiteral(ParserString ps) { StringBuffer str=new StringBuffer(); ps.removeSpace(); char c; while(!ps.isAfterLast()) { c=ps.getCurrent(); if(isSpace(c) || c==',') break; str.append(c); ps.next(); } return register(new Literal(str.toString())); } private boolean isSpace(char c) { return c==' ' || c=='\t' || c=='\n' || c=='\b'; } /*public static void main(String[] args) { QueryParser qp = new QueryParser(); qp.parseOp("aaa zzz not bbb and ccc"); print.out(qp.getLiteralSearchedTerms()); if(true) return; print.out(qp.parse("\"abc\"")); print.out(qp.parse("abc")); print.out(qp.parse("abc def")); print.out(qp.parse("abc def")); print.out(qp.parse("abc and def")); print.out(qp.parse("\"\"\"abc\"\"\"")); print.out(qp.parse("\"abc\" susi or peter")); print.out(qp.parse("abc susi or peter")); print.out(qp.parse("abc or susi or peter")); print.out(qp.parse("*abc susi and peter or \"abc\"* , xxx,yy*")); print.out(qp.parse("xxx,y\"y*")); print.out(qp.parse("xxx y\"y*")); print.out(qp.parse("")); print.out(qp.parse("per or")); print.out(qp.parse("per and")); print.out(qp.parse("per not")); print.out(qp.parse("andi per not susi")); print.out(qp.parse("\"kinderhort test\"")); }*/ public Literal register(Literal literal) { list.add(literal); return literal; } public Literal[] getLiteralSearchedTerms() { return (Literal[]) list.toArray(new Literal[list.size()]); } public String[] getStringSearchedTerms() { Iterator it = list.iterator(); String[] rtn=new String[list.size()]; int i=0; while(it.hasNext()) { rtn[i++]=it.next().toString(); } return rtn; } }