/** * */ package com.xored.glance.internal.ui.search; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * @author Yuri Strot */ public class SearchUtils { private static class CamelCaseBuilder extends RegExpBulder { private boolean wordPrev = false; @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 static class RegExpBulder { public String asRegExp(char ch) { switch (ch) { // the backslash case '\\': return "\\\\"; //$NON-NLS-1$ // characters that need to be escaped in the regex. case '(': case ')': case '{': case '}': case '.': case '[': case ']': case '$': case '^': case '+': case '|': case '?': case '*': StringBuffer buffer = new StringBuffer(); buffer.append('\\'); buffer.append(ch); return buffer.toString(); default: return null; } } } private static final String CAMEL_CASE_SKIP = "\\w*"; 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); } /** * 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); 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(); } /** * 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(); } }