<commit_before>/*
 * UniTime 3.2 (University Timetabling Application)
 * Copyright (C) 2010, UniTime LLC, and individual contributors
 * as indicated by the @authors tag.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
*/
package org.unitime.timetable.gwt.server;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author <NAME>
 */
public class Query implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Term iQuery = null;
	
	public Query(String query) {
		iQuery = parse(query == null ? "" : query.trim());
	}
	
	public boolean match(TermMatcher m) {
		return iQuery.match(m);
	}
	
	public String toString() {
		return iQuery.toString();
	}
	
	public String toString(QueryFormatter f) {
		return iQuery.toString(f);
	}
	
	public boolean hasAttribute(String... attr) {
		for (String a: attr)
			if (iQuery.hasAttribute(a)) return true;
		return false;
	}
	
	private static List<String> split(String query, String... splits) {
		List<String> ret = new ArrayList<String>();
		int bracket = 0;
		boolean quot = false;
		int last = 0;
		boolean white = false;
		loop: for (int i = 0; i < query.length(); i++) {
			if (query.charAt(i) == '"') {
				quot = !quot;
				white = !quot;
				continue;
			}
			if (!quot && query.charAt(i) == '(') { bracket ++; white = false; continue; }
			if (!quot && query.charAt(i) == ')') { bracket --; white = true; continue; }
			if (quot || bracket > 0 || (!white && query.charAt(i) != ' ')) {
				white = (query.charAt(i) == ' ');
				continue;
			}
			white = (query.charAt(i) == ' ');
			String q = query.substring(i).toLowerCase();
			for (String split: splits) {
				if (split.isEmpty() || q.startsWith(split + " ") || q.startsWith(split + "\"") || q.startsWith(split + "(")) {
					String x = query.substring(last, i).trim();
					if (split.isEmpty() && x.endsWith(":")) continue;
					if (!x.isEmpty()) ret.add(x);
					last = i + split.length();
					if (!split.isEmpty())
						i += split.length() - 1;
					continue loop;
				}
			}
		}
		String x = query.substring(last).trim();
		if (!x.isEmpty()) ret.add(x);
		return ret;
	}

	private static Term parse(String query) {
		List<String> splits;
		splits = split(query, "and", "&&", "&");
		if (splits.size() > 1) {
			CompositeTerm t = new AndTerm();
			for (String q: splits)
				t.add(parse(q));
			return t;
		}
		splits = split(query, "or", "||", "|");
		if (splits.size() > 1) {
			CompositeTerm t = new OrTerm();
			for (String q: splits)
				t.add(parse(q));
			return t;
		}
		splits = split(query, "");
		if (splits.size() > 1) {
			CompositeTerm t = new AndTerm();
			boolean not = false;
			for (String q: splits) {
				if (q.equalsIgnoreCase("not") || q.equals("!")) { not = true; continue; }
				if (q.startsWith("!(")) {
					q = q.substring(1); not = true;
				} else if (q.toLowerCase().startsWith("not(")) {
					q = q.substring(3); not = true;
				}
				if (not) {
					t.add(new NotTerm(parse(q)));
					not = false;
				} else {
					t.add(parse(q));
				}
			}
			return t;
		}
		if (query.startsWith("(") && query.endsWith(")")) return parse(query.substring(1, query.length() - 1).trim());
		if (query.startsWith("\"") && query.endsWith("\"")) return new AtomTerm(null, query.substring(1, query.length() - 1).trim());
		int idx = query.indexOf(':');
		if (idx >= 0) {
			return new AtomTerm(query.substring(0, idx).trim().toLowerCase(), query.substring(idx + 1).trim());
		} else {
			return new AtomTerm(null, query);
		}<commit_msg>Query:  - fixed StringIndexOutOfBoundsException when the given query is a single quotation mark<commit_after>/*
 * UniTime 3.2 (University Timetabling Application)
 * Copyright (C) 2010, UniTime LLC, and individual contributors
 * as indicated by the @authors tag.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
*/
package org.unitime.timetable.gwt.server;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author <NAME>
 */
public class Query implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private Term iQuery = null;
	
	public Query(String query) {
		iQuery = parse(query == null ? "" : query.trim());
	}
	
	public boolean match(TermMatcher m) {
		return iQuery.match(m);
	}
	
	public String toString() {
		return iQuery.toString();
	}
	
	public String toString(QueryFormatter f) {
		return iQuery.toString(f);
	}
	
	public boolean hasAttribute(String... attr) {
		for (String a: attr)
			if (iQuery.hasAttribute(a)) return true;
		return false;
	}
	
	private static List<String> split(String query, String... splits) {
		List<String> ret = new ArrayList<String>();
		int bracket = 0;
		boolean quot = false;
		int last = 0;
		boolean white = false;
		loop: for (int i = 0; i < query.length(); i++) {
			if (query.charAt(i) == '"') {
				quot = !quot;
				white = !quot;
				continue;
			}
			if (!quot && query.charAt(i) == '(') { bracket ++; white = false; continue; }
			if (!quot && query.charAt(i) == ')') { bracket --; white = true; continue; }
			if (quot || bracket > 0 || (!white && query.charAt(i) != ' ')) {
				white = (query.charAt(i) == ' ');
				continue;
			}
			white = (query.charAt(i) == ' ');
			String q = query.substring(i).toLowerCase();
			for (String split: splits) {
				if (split.isEmpty() || q.startsWith(split + " ") || q.startsWith(split + "\"") || q.startsWith(split + "(")) {
					String x = query.substring(last, i).trim();
					if (split.isEmpty() && x.endsWith(":")) continue;
					if (!x.isEmpty()) ret.add(x);
					last = i + split.length();
					if (!split.isEmpty())
						i += split.length() - 1;
					continue loop;
				}
			}
		}
		String x = query.substring(last).trim();
		if (!x.isEmpty()) ret.add(x);
		return ret;
	}

	private static Term parse(String query) {
		List<String> splits;
		splits = split(query, "and", "&&", "&");
		if (splits.size() > 1) {
			CompositeTerm t = new AndTerm();
			for (String q: splits)
				t.add(parse(q));
			return t;
		}
		splits = split(query, "or", "||", "|");
		if (splits.size() > 1) {
			CompositeTerm t = new OrTerm();
			for (String q: splits)
				t.add(parse(q));
			return t;
		}
		splits = split(query, "");
		if (splits.size() > 1) {
			CompositeTerm t = new AndTerm();
			boolean not = false;
			for (String q: splits) {
				if (q.equalsIgnoreCase("not") || q.equals("!")) { not = true; continue; }
				if (q.startsWith("!(")) {
					q = q.substring(1); not = true;
				} else if (q.toLowerCase().startsWith("not(")) {
					q = q.substring(3); not = true;
				}
				if (not) {
					t.add(new NotTerm(parse(q)));
					not = false;
				} else {
					t.add(parse(q));
				}
			}
			return t;
		}
		if (query.startsWith("(") && query.endsWith(")")) return parse(query.substring(1, query.length() - 1).trim());
		if (query.startsWith("\"") && query.endsWith("\"") && query.length() >= 2) return new AtomTerm(null, query.substring(1, query.length() - 1).trim());
		int idx = query.indexOf(':');
		if (idx >= 0) {
			return new AtomTerm(query.substring(0, idx).trim().toLowerCase(), query.substring(idx + 1).trim());
		} else {
			return new AtomTerm(null, query);
		}
{'fraction_non_alphanumeric': 0.16771513353115727, 'fraction_numerical': 0.006053412462908012, 'mean_word_length': 3.213, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4735851', 'n_tokens_mistral': 3204, 'n_tokens_neox': 2774, 'n_words': 827}