Как отменить эскейп строкового литерала Java в Java?
я обрабатываю некоторый исходный код Java с помощью Java. Я извлекаю строковые литералы и передаю их в функцию, принимающую строку. Проблема в том, что мне нужно пройти неэкранированные версии строки в функцию (т. е. это означает преобразование n
к новой строке, и в одном
и т. д.).
есть ли функция внутри Java API, которая делает это? Если нет, Могу ли я получить такую функциональность из какой-либо библиотеки? Очевидно, что компилятор Java должен сделать это преобразование.
PS- в случае, если кто-то хочет знать: я пытаюсь unobfuscate строковые литералы в декомпилированных запутанных Java-файлов
11 ответов:
EDIT: вы можете скачать полный источник для функции, которую я обсуждаю ниже. Я также обсуждаю это более подробно в ответ.
Проблема
The
org.apache.commons.lang.StringEscapeUtils.unescapeJava()
данный здесь как "ответ" на самом деле очень мало помогает вообще.
- вы должны обеспечить загрузку еще одного гигантского файла jar с прикладами cruft, которые вам не нужны или не нужны.
- он лицензия. Некоторые люди не хотят беспокоиться о лицензии, независимо от того, насколько хорошо или насколько плохо на самом деле.
- он забывает о
на null.
- он не обрабатывает восьмеричной на всех.
- он не может справиться с видами побегов, допущенных
java.util.regex.Pattern.compile()
и все, что использует его, в том числе\a
,\e
и особенно\cX
.- он не поддерживает логические кодовые точки Юникода по номеру, только для идиотских UTF-16 повреждение головного мозга.
- это написано каким-то чертовым идиотом, который даже не знает разницы между полоснуть и обратная косая черта.
- исходный код полон раздражающих возвратов каретки.
- это написано, чтобы взять
writer
аргумент, так что если вы не передадите его один он все равно должен создать манекенStringWriter
для вывода, а затем преобразовать, что передать обратно к вам.- это выглядит как код UCS-2, а не код UTF-16: они используют амортизированные
charAt
интерфейс вместоcodePoint
интерфейс, тем самым распространяя заблуждение, что Javachar
гарантированно содержит символ Юникода. Это не так. Им только сходит с рук эта слепота к астральным планам, потому что никакой суррогат UTF-16 не будет искать то, что они ищут.как и многие другие пункты, их смущает незнание названий кодовых пунктов
U+2F
иU+5C
не внушает доверия в них вообще ничего нет. Для протокола:/ 47 002F SOLIDUS = slash, virgule x (latin letter dental click - 01C0) x (combining long solidus overlay - 0338) x (fraction slash - 2044) x (division slash - 2215) \ 92 005C REVERSE SOLIDUS = backslash x (combining reverse solidus overlay - 20E5) x (set minus - 2216)
Решение
так что сегодня утром я наконец-то надоело не уметь читать в строках со встроенными в них побегами. Мне это было нужно для написания набора тестов для более крупного и интересного проекта: прозрачное преобразование Java неопровержимо Unicode-невежественные регулярные выражения в версии, где вы можете использовать все
\w
,\W
,\s
,\S
,\v
,\V
,\h
,\H
,\d
,\D
,\b
,\B
,\X
и\R
в ваших шаблонах и иметь их на самом деле правильно работать с Unicode. Все, что я делаю, это переписать строку шаблона; он по-прежнему компилируется со стандартным N NN \N \NN \NNN * Can range up to !7 not 7 * * TODO: add !\o{NNNNN} * last Unicode is 4177777 * maxint is 37777777777 * * Control chars: ?\cX * Means: ord(X) ^ ord('@') * * Old hex escapes: \xXX * unbraced must be 2 xdigits * * Perl hex escapes: !\x{XXX} braced may be 1-8 xdigits * NB: proper Unicode never needs more than 6, as highest * valid codepoint is 0x10FFFF, not maxint 0xFFFFFFFF * * Lame Java escape: \[IDIOT JAVA PREPROCESSOR]uXXXX must be * exactly 4 xdigits; * * I can't write XXXX in this comment where it belongs * because the damned Java Preprocessor can't mind its * own business. Idiots! * * Lame Python escape: !\UXXXXXXXX must be exactly 8 xdigits * * TODO: Perl translation escapes: \Q \U \L \E \[IDIOT JAVA PREPROCESSOR]u \l * These are not so important to cover if you're passing the * result to Pattern.compile(), since it handles them for you * further downstream. Hm, what about \[IDIOT JAVA PREPROCESSOR]u? * */ public final static String unescape_perl_string(String oldstr) { /* * In contrast to fixing Java's broken regex charclasses, * this one need be no bigger, as unescaping shrinks the string * here, where in the other one, it grows it. */ StringBuffer newstr = new StringBuffer(oldstr.length()); boolean saw_backslash = false; for (int i = 0; i < oldstr.length(); i++) { int cp = oldstr.codePointAt(i); if (oldstr.codePointAt(i) > Character.MAX_VALUE) { i++; /****WE HATES UTF-16! WE HATES IT FOREVERSES!!!****/ } if (!saw_backslash) { if (cp == '\') { saw_backslash = true; } else { newstr.append(Character.toChars(cp)); } continue; /* switch */ } if (cp == '\') { saw_backslash = false; newstr.append('\'); newstr.append('\'); continue; /* switch */ } switch (cp) { case 'r': newstr.append('\r'); break; /* switch */ case 'n': newstr.append('\n'); break; /* switch */ case 'f': newstr.append('\f'); break; /* switch */ /* PASS a \b THROUGH!! */ case 'b': newstr.append("\b"); break; /* switch */ case 't': newstr.append('\t'); break; /* switch */ case 'a': newstr.append('7'); break; /* switch */ case 'e': newstr.append('3'); break; /* switch */ /* * A "control" character is what you get when you xor its * codepoint with '@'==64. This only makes sense for ASCII, * and may not yield a "control" character after all. * * Strange but true: "\c{" is ";", "\c}" is "=", etc. */ case 'c': { if (++i == oldstr.length()) { die("trailing \c"); } cp = oldstr.codePointAt(i); /* * don't need to grok surrogates, as next line blows them up */ if (cp > 0x7f) { die("expected ASCII after \c"); } newstr.append(Character.toChars(cp ^ 64)); break; /* switch */ } case '8': case '9': die("illegal octal digit"); /* NOTREACHED */ /* * may be 0 to 2 octal digits following this one * so back up one for fallthrough to next case; * unread this digit and fall through to next case. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': --i; /* FALLTHROUGH */ /* * Can have 0, 1, or 2 octal digits following a 0 * this permits larger values than octal 377, up to * octal 777. */ case '0': { if (i+1 == oldstr.length()) { /* found at end of string */ newstr.append(Character.toChars(0)); break; /* switch */ } i++; int digits = 0; int j; for (j = 0; j <= 2; j++) { if (i+j == oldstr.length()) { break; /* for */ } /* safe because will unread surrogate */ int ch = oldstr.charAt(i+j); if (ch < '0' || ch > '7') { break; /* for */ } digits++; } if (digits == 0) { --i; newstr.append(''); break; /* switch */ } int value = 0; try { value = Integer.parseInt( oldstr.substring(i, i+digits), 8); } catch (NumberFormatException nfe) { die("invalid octal value for \0 escape"); } newstr.append(Character.toChars(value)); i += digits-1; break; /* switch */ } /* end case '0' */ case 'x': { if (i+2 > oldstr.length()) { die("string too short for \x escape"); } i++; boolean saw_brace = false; if (oldstr.charAt(i) == '{') { /* ^^^^^^ ok to ignore surrogates here */ i++; saw_brace = true; } int j; for (j = 0; j < 8; j++) { if (!saw_brace && j == 2) { break; /* for */ } /* * ASCII test also catches surrogates */ int ch = oldstr.charAt(i+j); if (ch > 127) { die("illegal non-ASCII hex digit in \x escape"); } if (saw_brace && ch == '}') { break; /* for */ } if (! ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) ) { die(String.format( "illegal hex digit #%d '%c' in \x", ch, ch)); } } if (j == 0) { die("empty braces in \x{} escape"); } int value = 0; try { value = Integer.parseInt(oldstr.substring(i, i+j), 16); } catch (NumberFormatException nfe) { die("invalid hex value for \x escape"); } newstr.append(Character.toChars(value)); if (saw_brace) { j++; } i += j-1; break; /* switch */ } case 'u': { if (i+4 > oldstr.length()) { die("string too short for \u escape"); } i++; int j; for (j = 0; j < 4; j++) { /* this also handles the surrogate issue */ if (oldstr.charAt(i+j) > 127) { die("illegal non-ASCII hex digit in \u escape"); } } int value = 0; try { value = Integer.parseInt( oldstr.substring(i, i+j), 16); } catch (NumberFormatException nfe) { die("invalid hex value for \u escape"); } newstr.append(Character.toChars(value)); i += j-1; break; /* switch */ } case 'U': { if (i+8 > oldstr.length()) { die("string too short for \U escape"); } i++; int j; for (j = 0; j < 8; j++) { /* this also handles the surrogate issue */ if (oldstr.charAt(i+j) > 127) { die("illegal non-ASCII hex digit in \U escape"); } } int value = 0; try { value = Integer.parseInt(oldstr.substring(i, i+j), 16); } catch (NumberFormatException nfe) { die("invalid hex value for \U escape"); } newstr.append(Character.toChars(value)); i += j-1; break; /* switch */ } default: newstr.append('\'); newstr.append(Character.toChars(cp)); /* * say(String.format( * "DEFAULT unrecognized escape %c passed through", * cp)); */ break; /* switch */ } saw_backslash = false; } /* weird to leave one at the end */ if (saw_backslash) { newstr.append('\'); } return newstr.toString(); } /* * Return a string "U+XX.XXX.XXXX" etc, where each XX set is the * xdigits of the logical Unicode code point. No bloody brain-damaged * UTF-16 surrogate crap, just true logical characters. */ public final static String uniplus(String s) { if (s.length() == 0) { return ""; } /* This is just the minimum; sb will grow as needed. */ StringBuffer sb = new StringBuffer(2 + 3 * s.length()); sb.append("U+"); for (int i = 0; i < s.length(); i++) { sb.append(String.format("%X", s.codePointAt(i))); if (s.codePointAt(i) > Character.MAX_VALUE) { i++; /****WE HATES UTF-16! WE HATES IT FOREVERSES!!!****/ } if (i+1 < s.length()) { sb.append("."); } } return sb.toString(); } private static final void die(String foa) { throw new IllegalArgumentException(foa); } private static final void say(String what) { System.out.println(what); }как любой может ясно видеть из кода Java выше, я действительно программист C-Java is что-нибудь но мой любимый язык. Боюсь, что мне действительно придется встать на сторону Роб Пайк в своем знаменитом public static void говорить на этот один.
’Nuff сказал.
в любом случае, это всего лишь быстрый утренний хакер, но если это помогает другим, вы можете это сделать - без каких-либо условий. Если вы улучшите его, Я бы хотел, чтобы вы прислали мне свои улучшения, но вам, конечно, не нужно.
можно использовать
String unescapeJava(String)
методStringEscapeUtils
С Apache Commons Lang.вот пример фрагмента:
String in = "a\tb\n\\"c\\""; System.out.println(in); // a\tb\n\"c\" String out = StringEscapeUtils.unescapeJava(in); System.out.println(out); // a b // "c"
класс утилиты имеет методы для экранирования и unescape строк для Java, Java Script, HTML, XML и SQL. Он также имеет перегрузки, которые записывает непосредственно в
java.io.Writer
.
предостережения
похоже
StringEscapeUtils
обрабатывает Unicode экранирует с однимu
, но не восьмеричные побеги, или Unicode убегает с постороннимu
s./* Unicode escape test #1: PASS */ System.out.println( "\u0030" ); // 0 System.out.println( StringEscapeUtils.unescapeJava("\u0030") ); // 0 System.out.println( "\u0030".equals(StringEscapeUtils.unescapeJava("\u0030")) ); // true /* Octal escape test: FAIL */ System.out.println( "" ); // % System.out.println( StringEscapeUtils.unescapeJava("\45") ); // 45 System.out.println( "".equals(StringEscapeUtils.unescapeJava("\45")) ); // false /* Unicode escape test #2: FAIL */ System.out.println( "\uu0030" ); // 0 System.out.println( StringEscapeUtils.unescapeJava("\uu0030") ); // throws NestableRuntimeException: // Unable to parse unicode value: u003
цитата из JLS:
Восьмеричные экранирования предусмотрены для совместимости с C, но могут выражать только значения Unicode
\u0000
через\u00FF
, поэтому обычно предпочтительны эскейпы Unicode.если ваша строка может содержать восьмеричные escapes, вы можете сначала преобразовать их в Unicode escapes или использовать другой подход.
в посторонний
u
также описана следующим образом:язык программирования Java определяет стандартный способ преобразования программы, написанной в Юникоде, в ASCII, который изменяет программу в форму, которая может быть обработана средствами на основе ASCII. Преобразование включает в себя преобразование любых экранирований Unicode в исходном тексте программы в ASCII путем добавления дополнительного
u
-например,\uxxxx
становится\uuxxxx
- при одновременном преобразовании символов, отличных от ASCII исходный текст в Unicode экранирует, содержащий по одному u каждый.эта преобразованная версия одинаково приемлема для компилятора для языка программирования Java и представляет собой точно такую же программу. Точный источник Юникода может быть позже восстановлен из этой формы ASCII путем преобразования каждой escape-последовательности, где несколько
u
' s присутствуют в последовательности символов Юникода с одним меньшеu
, одновременно Преобразуя каждую escape-последовательность с помощью одногоu
к соответствующему одиночному символу Юникода.если ваша строка может содержать Unicode escapes с extraneous
u
, то вам также может потребоваться предварительно обработать это перед использованиемStringEscapeUtils
.в качестве альтернативы вы можете попробовать написать свой собственный строковый литерал Java unescaper с нуля, убедившись, что следуете точным спецификациям JLS.
ссылки
столкнулся с подобной проблемой, также не был удовлетворен представленными решениями и реализовал это сам.
также доступна в качестве сути на Github:
/** * Unescapes a string that contains standard Java escape sequences. * <ul> * <li><strong>\b \f \n \r \t \" \'</strong> : * BS, FF, NL, CR, TAB, double and single quote.</li> * <li><strong>\X \XX \XXX</strong> : Octal character * specification (0 - 377, 0x00 - 0xFF).</li> * <li><strong>\uXXXX</strong> : Hexadecimal based Unicode character.</li> * </ul> * * @param st * A string optionally containing standard java escape sequences. * @return The translated string. */ public String unescapeJavaString(String st) { StringBuilder sb = new StringBuilder(st.length()); for (int i = 0; i < st.length(); i++) { char ch = st.charAt(i); if (ch == '\') { char nextChar = (i == st.length() - 1) ? '\' : st .charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' && st.charAt(i + 1) <= '7') { code += st.charAt(i + 1); i++; if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' && st.charAt(i + 1) <= '7') { code += st.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch (nextChar) { case '\': ch = '\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\"': ch = '\"'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= st.length() - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + st.charAt(i + 2) + st.charAt(i + 3) + st.charAt(i + 4) + st.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; } i++; } sb.append(ch); } return sb.toString(); }
С http://commons.apache.org/lang/:
StringEscapeUtils.unescapeJava(String str)
Я знаю, что этот вопрос был старым, но я хотел решение, которое не включает библиотеки за пределами тех, которые включены JRE6 (т. е. Apache Commons не приемлем), и я придумал простое решение, используя встроенный
java.io.StreamTokenizer
:import java.io.*; // ... String literal = "\"Has \\"\\\\t\\" & isn\\'t \\r\\n on 1 line.\""; StreamTokenizer parser = new StreamTokenizer(new StringReader(literal)); String result; try { parser.nextToken(); if (parser.ttype == '"') { result = parser.sval; } else { result = "ERROR!"; } } catch (IOException e) { result = e.toString(); } System.out.println(result);
выход:
Has "\ " & isn't on 1 line.
Я немного опоздал на это, но я думал, что предоставлю свое решение, так как мне нужна та же функциональность. Я решил использовать API компилятора Java, который делает его медленнее, но делает результаты точными. В основном я живу создать класс, а затем вернуть результаты. Вот метод:
public static String[] unescapeJavaStrings(String... escaped) { //class name final String className = "Temp" + System.currentTimeMillis(); //build the source final StringBuilder source = new StringBuilder(100 + escaped.length * 20). append("public class ").append(className).append("{\n"). append("\tpublic static String[] getStrings() {\n"). append("\t\treturn new String[] {\n"); for (String string : escaped) { source.append("\t\t\t\""); //we escape non-escaped quotes here to be safe // (but something like \" will fail, oh well for now) for (int i = 0; i < string.length(); i++) { char chr = string.charAt(i); if (chr == '"' && i > 0 && string.charAt(i - 1) != '\') { source.append('\'); } source.append(chr); } source.append("\",\n"); } source.append("\t\t};\n\t}\n}\n"); //obtain compiler final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //local stream for output final ByteArrayOutputStream out = new ByteArrayOutputStream(); //local stream for error ByteArrayOutputStream err = new ByteArrayOutputStream(); //source file JavaFileObject sourceFile = new SimpleJavaFileObject( URI.create("string:///" + className + Kind.SOURCE.extension), Kind.SOURCE) { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return source; } }; //target file final JavaFileObject targetFile = new SimpleJavaFileObject( URI.create("string:///" + className + Kind.CLASS.extension), Kind.CLASS) { @Override public OutputStream openOutputStream() throws IOException { return out; } }; //file manager proxy, with most parts delegated to the standard one JavaFileManager fileManagerProxy = (JavaFileManager) Proxy.newProxyInstance( StringUtils.class.getClassLoader(), new Class[] { JavaFileManager.class }, new InvocationHandler() { //standard file manager to delegate to private final JavaFileManager standard = compiler.getStandardFileManager(null, null, null); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("getJavaFileForOutput".equals(method.getName())) { //return the target file when it's asking for output return targetFile; } else { return method.invoke(standard, args); } } }); //create the task CompilationTask task = compiler.getTask(new OutputStreamWriter(err), fileManagerProxy, null, null, null, Collections.singleton(sourceFile)); //call it if (!task.call()) { throw new RuntimeException("Compilation failed, output:\n" + new String(err.toByteArray())); } //get the result final byte[] bytes = out.toByteArray(); //load class Class<?> clazz; try { //custom class loader for garbage collection clazz = new ClassLoader() { protected Class<?> findClass(String name) throws ClassNotFoundException { if (name.equals(className)) { return defineClass(className, bytes, 0, bytes.length); } else { return super.findClass(name); } } }.loadClass(className); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } //reflectively call method try { return (String[]) clazz.getDeclaredMethod("getStrings").invoke(null); } catch (Exception e) { throw new RuntimeException(e); } }
Он принимает массив, так что вы можете unescape в пакетах. Таким образом, следующий простой тест завершается успешно:
public static void main(String[] meh) { if ("1\n".equals(unescapeJavaStrings("1\02\03\n")[0])) { System.out.println("Success"); } else { System.out.println("Failure"); } }
я столкнулся с той же проблемой, но я не был очарован ни одним из решений, которые я нашел здесь. Итак, я написал тот, который повторяет символы строки, используя сопоставитель, чтобы найти и заменить escape-последовательности. Это решение предполагает правильно отформатированный ввод. То есть он счастливо пропускает бессмысленные экранирования и декодирует экранирование Unicode для подачи строки и возврата каретки (которые в противном случае не могут отображаться в символьном литерале или строковом литерале из-за определения таких литералы и порядок фаз перевода для исходного кода Java). Извините, код немного упакован для краткости.
import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Decoder { // The encoded character of each character escape. // This array functions as the keys of a sorted map, from encoded characters to decoded characters. static final char[] ENCODED_ESCAPES = { '\"', '\'', '\', 'b', 'f', 'n', 'r', 't' }; // The decoded character of each character escape. // This array functions as the values of a sorted map, from encoded characters to decoded characters. static final char[] DECODED_ESCAPES = { '\"', '\'', '\', '\b', '\f', '\n', '\r', '\t' }; // A pattern that matches an escape. // What follows the escape indicator is captured by group 1=character 2=octal 3=Unicode. static final Pattern PATTERN = Pattern.compile("\\(?:(b|t|n|f|r|\\"|\\'|\\)|((?:[0-3]?[0-7])?[0-7])|u+(\p{XDigit}{4}))"); public static CharSequence decodeString(CharSequence encodedString) { Matcher matcher = PATTERN.matcher(encodedString); StringBuffer decodedString = new StringBuffer(); // Find each escape of the encoded string in succession. while (matcher.find()) { char ch; if (matcher.start(1) >= 0) { // Decode a character escape. ch = DECODED_ESCAPES[Arrays.binarySearch(ENCODED_ESCAPES, matcher.group(1).charAt(0))]; } else if (matcher.start(2) >= 0) { // Decode an octal escape. ch = (char)(Integer.parseInt(matcher.group(2), 8)); } else /* if (matcher.start(3) >= 0) */ { // Decode a Unicode escape. ch = (char)(Integer.parseInt(matcher.group(3), 16)); } // Replace the escape with the decoded character. matcher.appendReplacement(decodedString, Matcher.quoteReplacement(String.valueOf(ch))); } // Append the remainder of the encoded string to the decoded string. // The remainder is the longest suffix of the encoded string such that the suffix contains no escapes. matcher.appendTail(decodedString); return decodedString; } public static void main(String... args) { System.out.println(decodeString(args[0])); } }
Я должен отметить, что Apache Commons Lang3, похоже, не страдает слабостями, указанными в принятом решении. То есть,
StringEscapeUtils
Кажется, обрабатывать восьмеричные побеги и несколькоu
символы Unicode экранируются. Это означает, что если у вас нет какой-то горящей причины избегать Apache Commons, вы, вероятно, должны использовать его, а не мое решение (или любое другое решение здесь).
org.apache.commons.lang3.StringEscapeUtils
из commons-lang3 теперь помечен как устаревший. Вы можете использоватьorg.apache.commons.text.StringEscapeUtils#unescapeJava(String)
вместо. Это требует дополнительного зависимостей Maven:<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.4</version> </dependency>
и, кажется, обрабатывать еще несколько особых случаев, например, отменяет:
- экранированные обратные косые черты, одинарные и двойные кавычки
- экранированные восьмеричные и юникодные значения
\b
,\n
,\t
,\f
,\r
если Вы читаете Unicode экранированные символы из файла, то вам будет трудно сделать это, потому что строка будет прочитана буквально вместе с escape для задней косой черты:
my_file.txt
Blah blah... Column delimiter=; Word delimiter=\u0020 #This is just unicode for whitespace .. more stuff
здесь, когда вы читаете строку 3 из файла строка / строка будет иметь:
"Word delimiter=\u0020 #This is just unicode for whitespace"
и char[] в строке появится сообщение:
{...., '=', '\', 'u', '0', '0', '2', '0', ' ', '#', 't', 'h', ...}
Commons StringUnescape не будет unescape это для вас (я пробовал unescapeXml ()). Вы будете иметь сделать это вручную как описано здесь.
Итак, подстрока "\u0020 "должна стать 1 одиночным символом'\u0020'
но если вы используете это "\u0020", чтобы сделать
String.split("... ..... ..", columnDelimiterReadFromFile)
который действительно использует регулярное выражение внутри, он будет работать напрямую, потому что строка, считанная из файла, была экранирована и идеально подходит для использования в шаблоне регулярного выражения!! (В замешательстве?)
возможно, вы захотите взглянуть на реализацию Eclipse Stringliteral.