/**
*
*/
package com.xored.glance.internal.ui.search;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* @author Yuri Strot
*
*/
public class SearchUtils {
public static Pattern createPattern(String pattern, boolean caseSensitive,
boolean regExSearch, boolean wordPrefix, boolean camelCase) {
if (pattern == null || pattern.length() == 0)
return null;
int patternFlags = 0;
if (!caseSensitive)
patternFlags |= Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
if (regExSearch) {
patternFlags |= Pattern.MULTILINE;
pattern = substituteLinebreak(pattern);
} else {
RegExpBulder builder = camelCase ? new CamelCaseBuilder()
: new RegExpBulder();
pattern = asRegPattern(pattern, builder);
if (wordPrefix) {
pattern = "\\b" + pattern; //$NON-NLS-1$
}
}
return Pattern.compile(pattern, patternFlags);
}
/**
* Substitutes \R in a regex find pattern with (?>\r\n?|\n)
*
* @param findString
* the original find pattern
* @return the transformed find pattern
* @throws PatternSyntaxException
* if \R is added at an illegal position (e.g. in a character
* set)
*/
private static String substituteLinebreak(String findString)
throws PatternSyntaxException {
int length = findString.length();
StringBuffer buf = new StringBuffer(length);
int inCharGroup = 0;
int inBraces = 0;
boolean inQuote = false;
for (int i = 0; i < length; i++) {
char ch = findString.charAt(i);
switch (ch) {
case '[':
buf.append(ch);
if (!inQuote)
inCharGroup++;
break;
case ']':
buf.append(ch);
if (!inQuote)
inCharGroup--;
break;
case '{':
buf.append(ch);
if (!inQuote && inCharGroup == 0)
inBraces++;
break;
case '}':
buf.append(ch);
if (!inQuote && inCharGroup == 0)
inBraces--;
break;
case '\\':
if (i + 1 < length) {
char ch1 = findString.charAt(i + 1);
if (inQuote) {
if (ch1 == 'E')
inQuote = false;
buf.append(ch).append(ch1);
i++;
} else if (ch1 == 'R') {
if (inCharGroup > 0 || inBraces > 0) {
throw new PatternSyntaxException(
"Illegal position for \\R", findString, i);
}
buf.append("(?>\\r\\n?|\\n)"); //$NON-NLS-1$
i++;
} else {
if (ch1 == 'Q') {
inQuote = true;
}
buf.append(ch).append(ch1);
i++;
}
} else {
buf.append(ch);
}
break;
default:
buf.append(ch);
break;
}
}
return buf.toString();
}
/**
* Converts a non-regex string to a pattern that can be used with the regex
* search engine.
*
* @param string
* the non-regex pattern
* @return the string converted to a regex pattern
*/
private static String asRegPattern(String string, RegExpBulder builder) {
StringBuffer out = new StringBuffer(string.length());
boolean quoting = false;
for (int i = 0, length = string.length(); i < length; i++) {
char ch = string.charAt(i);
String re = builder.asRegExp(ch);
if (re != null) {
if (quoting) {
out.append("\\E"); //$NON-NLS-1$
quoting = false;
}
out.append(re); //$NON-NLS-1$
continue;
}
if (!quoting) {
out.append("\\Q"); //$NON-NLS-1$
quoting = true;
}
out.append(ch);
}
if (quoting)
out.append("\\E"); //$NON-NLS-1$
return out.toString();
}
private static class RegExpBulder {
public String asRegExp(char ch) {
if (ch == '\\') {
return "\\\\";
}
return null;
}
}
private static class CamelCaseBuilder extends RegExpBulder {
@Override
public String asRegExp(char ch) {
String regExp = super.asRegExp(ch);
if (regExp != null) {
wordPrev = false;
} else {
boolean word = isWord(ch);
if (word && wordPrev) {
regExp = CAMEL_CASE_SKIP + ch;
}
wordPrev = word;
}
return regExp;
}
private boolean isWord(char ch) {
return ch == '_' || Character.isLetterOrDigit(ch);
}
private boolean wordPrev = false;
}
private static final String CAMEL_CASE_SKIP = "\\w*";
}