Comment échapper à une chaîne de caractères Java en Java?

Je traite du code source Java en utilisant Java. J’extrais les littéraux de chaîne et les achemine à une fonction qui prend une chaîne. Le problème est que je dois passer la version non échappée de la chaîne à la fonction (c.-à-d. Cela signifie convertir \n en une nouvelle ligne, et \\ en un seul \ , etc.).

Y a-t-il une fonction dans l’API Java qui fait cela? Sinon, puis-je obtenir une telle fonctionnalité à partir d’une bibliothèque? De toute évidence, le compilateur Java doit effectuer cette conversion.


PS – Au cas où quelqu’un voudrait savoir: j’essaie de décoiffer les littéraux de chaîne dans les fichiers Java décompilés et décompilés

EDIT: Vous pouvez télécharger la source complète pour la fonction dont je parle ci-dessous. J’en discute également plus en détail dans cette réponse .

Le problème

Le org.apache.commons.lang.SsortingngEscapeUtils.unescapeJava() donné ici comme «la réponse» est vraiment très peu utile.

  • Vous devez prévoir de charger un autre fichier jar gigantesque contenant des fichiers inutiles dont vous n’avez pas besoin ou que vous ne voulez pas.
  • Il a une licence. Certaines personnes ne veulent pas s’inquiéter d’une licence, quelle que soit sa qualité.
  • Il oublie à propos de \0 pour null.
  • Il ne gère pas d’octal du tout .
  • Il ne peut pas gérer les types d’échappements admis par java.util.regex.Pattern.comstack() et tout ce qui l’utilise, y compris \a , \e et surtout \cX .
  • Il ne prend pas en charge les points de code Unicode logiques par numéro, mais uniquement pour les dommages cérébraux UTF-16 idiots.
  • C’est écrit par un idiot qui ne sait même pas la différence entre une barre oblique et une barre oblique inverse .
  • Le code source est plein de retours chariot ennuyeux.
  • Il est écrit pour prendre un argument de SsortingngWriter , donc si vous ne le transmettez pas, il doit encore créer un SsortingngWriter fictif pour la sortie, puis le convertir pour vous le renvoyer.
  • Cela ressemble au code UCS-2, et non au code UTF-16: ils utilisent l’interface codePoint dépréciée à la place de l’interface codePoint , codePoint ainsi l’illusion qu’un caractère Java est garanti pour contenir un caractère Unicode. Ce n’est pas. Ils ne s’en tirent qu’avec cet aveuglement sur les plans astraux, car aucun substitut UTF-16 ne finira par chercher ce qu’ils cherchent.

Comme beaucoup d’autres points, leur ignorance embarrassante à propos des noms des points de code U+2F et U+5C ne leur donne aucune confiance. Pour le compte rendu:

  / 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) 

La solution

Donc, ce matin, j’en ai eu assez de ne plus pouvoir lire les chaînes avec des fuites incorporées. J’en avais besoin pour écrire la suite de tests pour un projet plus grand et plus intéressant: convertir de manière transparente les expressions régulières , ignorées par Unicode, indéfiniment Java en versions où vous pouvez utiliser tout \w , \W , \s , \S , \v , \V , \h , \H , \d , \D , \b , \B , \X et \R dans vos patterns et les faire fonctionner correctement avec Unicode. Tout ce que je fais, c’est réécrire la chaîne de motif; il comstack toujours avec la fonction standard java.util.regex.Pattern.comstack() , donc tout fonctionne comme prévu. Le détournement de chaîne passe intentionnellement n’importe quel \b travers, au cas où vous l’appeliez avant que vous appeliez la fonction de conversion pour que Java regex reconnaisse Unicode, puisque cela doit traiter \b dans le sens des limites.

Quoi qu’il en soit, voici la ficelle de la chaîne, qui, bien que moins intéressante de la paire, résout la question du PO sans toutes les irritations du code Apache. Il pouvait gérer un peu de resserrement dans quelques endroits, mais je l’ai rapidement piraté quelques heures avant le déjeuner, juste pour le faire fonctionner afin d’aider à piloter la suite de tests. L’autre fonction est beaucoup plus de travail: on m’a pris toute la journée hier, sacrément.

 /* * * unescape_perl_ssortingng() * * Tom Christiansen  * Sun Nov 28 12:55:24 MST 2010 * * It's completely ridiculous that there's no standard * unescape_java_ssortingng function. Since I have to do the * damn thing myself, I might as well make it halfway useful * by supporting things Java was too stupid to consider in * ssortingngs: * * => "?" items are additions to Java ssortingng escapes * but normal in Java regexes * * => "!" items are also additions to Java regex escapes * * Standard singletons: ?\a ?\e \f \n \r \t * * NB: \b is unsupported as backspace so it can pass-through * to the regex translator untouched; I refuse to make anyone * doublebackslash it as doublebackslashing is a Java idiocy * I desperately wish would die out. There are plenty of * other ways to write it: * * \cH, \12, \012, \x08 \x{8}, \u0008, \U00000008 * * Octal escapes: \0 \0N \0NN \N \NN \NNN * Can range up to !\777 not \377 * * 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.comstack(), since it handles them for you * further downstream. Hm, what about \[IDIOT JAVA PREPROCESSOR]u? * */ public final static Ssortingng unescape_perl_ssortingng(Ssortingng oldstr) { /* * In contrast to fixing Java's broken regex charclasses, * this one need be no bigger, as unescaping shrinks the ssortingng * here, where in the other one, it grows it. */ SsortingngBuffer newstr = new SsortingngBuffer(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('\007'); break; /* switch */ case 'e': newstr.append('\033'); 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 \0 at end of ssortingng */ 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('\0'); break; /* switch */ } int value = 0; try { value = Integer.parseInt( oldstr.subssortingng(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("ssortingng 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("ssortingng 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.subssortingng(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("ssortingng 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.subssortingng(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(Ssortingng.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.toSsortingng(); } /* * Return a ssortingng "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 Ssortingng uniplus(Ssortingng s) { if (s.length() == 0) { return ""; } /* This is just the minimum; sb will grow as needed. */ SsortingngBuffer sb = new SsortingngBuffer(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); } 

Comme tout le monde peut le voir clairement dans le code Java ci-dessus, je suis vraiment un programmeur C - Java est tout sauf mon langage préféré. Je crains vraiment de devoir côtoyer Rob Pike dans son célèbre discours sur le vide statique sur ce sujet.

"Nuff a dit.

Quoi qu’il en soit, ce n’est qu’un rapide piratage du matin, mais si cela aide les autres, vous êtes les bienvenus - sans aucune condition. Si vous l'améliorez, j'aimerais que vous m'envoyiez vos améliorations, mais vous n'en avez certainement pas besoin.

Vous pouvez utiliser la méthode Ssortingng unescapeJava(Ssortingng) de SsortingngEscapeUtils d’ Apache Commons Lang .

Voici un exemple d’extrait de code:

  Ssortingng in = "a\\tb\\n\\\"c\\\""; System.out.println(in); // a\tb\n\"c\" Ssortingng out = SsortingngEscapeUtils.unescapeJava(in); System.out.println(out); // ab // "c" 

La classe d’utilitaires dispose de méthodes permettant d’échapper et de supprimer les chaînes pour Java, Java Script, HTML, XML et SQL. Il a également des surcharges qui écrivent directement sur un java.io.Writer .


Mises en garde

On dirait que SsortingngEscapeUtils gère les échappements Unicode avec un u , mais pas les échappements octaux, ou Unicode s’échappe avec des us externes.

  /* Unicode escape test #1: PASS */ System.out.println( "\u0030" ); // 0 System.out.println( SsortingngEscapeUtils.unescapeJava("\\u0030") ); // 0 System.out.println( "\u0030".equals(SsortingngEscapeUtils.unescapeJava("\\u0030")) ); // true /* Octal escape test: FAIL */ System.out.println( "\45" ); // % System.out.println( SsortingngEscapeUtils.unescapeJava("\\45") ); // 45 System.out.println( "\45".equals(SsortingngEscapeUtils.unescapeJava("\\45")) ); // false /* Unicode escape test #2: FAIL */ System.out.println( "\uu0030" ); // 0 System.out.println( SsortingngEscapeUtils.unescapeJava("\\uu0030") ); // throws NestableRuntimeException: // Unable to parse unicode value: u003 

Une citation du JLS:

Les échappements octaux sont fournis pour la compatibilité avec C, mais ne peuvent exprimer que des valeurs Unicode \u0000 à \u00FF , les échappements Unicode sont donc généralement préférés.

Si votre chaîne peut contenir des échappements octaux, vous souhaiterez peut-être les convertir en échappements Unicode en premier, ou utiliser une autre approche.

L’extérieur est également documenté comme suit:

Le langage de programmation Java spécifie un moyen standard de transformer un programme écrit en Unicode en ASCII qui transforme un programme en une forme pouvant être traitée par des outils ASCII. La transformation implique la conversion en ASCII de toutes les fuites Unicode du texte source du programme en ajoutant un u supplémentaire, par exemple, \uxxxx devient \uuxxxx en convertissant simultanément les caractères non ASCII du texte source en fuites Unicode contenant un seul u .

Cette version transformée est également acceptable pour un compilateur pour le langage de programmation Java et représente exactement le même programme. La source Unicode exacte peut ensuite être restaurée à partir de cette forme ASCII en convertissant chaque séquence d’échappement où plusieurs u sont présents en une séquence de caractères Unicode avec un nombre inférieur, tout en convertissant simultanément chaque séquence d’échappement en un unique en Unicode unique correspondant. personnage.

Si votre chaîne peut contenir des échappements Unicode avec des éléments externes, vous devrez peut-être également effectuer un prétraitement avant d’utiliser SsortingngEscapeUtils .

Alternativement, vous pouvez essayer d’écrire votre propre chaîne de caractères Java à partir de zéro, en vous assurant de suivre les spécifications exactes de JLS.

Les références

  • JLS 3.3 Unicode Escapes
  • JLS 3.10.6 Séquences d’échappement pour les littéraux de caractères et de chaînes

Je suis tombé sur un problème similaire, je n’étais pas non plus satisfait des solutions présentées et je l’ai implémenté.

Aussi disponible sous forme de Gist sur Github :

 /** * Unescapes a ssortingng that contains standard Java escape sequences. * 
    *
  • \b \f \n \r \t \" \' : * BS, FF, NL, CR, TAB, double and single quote.
  • *
  • \X \XX \XXX : Octal character * specification (0 - 377, 0x00 - 0xFF).
  • *
  • \uXXXX : Hexadecimal based Unicode character.
  • *
* * @param st * A ssortingng optionally containing standard java escape sequences. * @return The translated ssortingng. */ public Ssortingng unescapeJavaSsortingng(Ssortingng st) { SsortingngBuilder sb = new SsortingngBuilder(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.toSsortingng(); }

Je sais que cette question était ancienne, mais je voulais une solution qui n’implique pas de bibliothèques en dehors de celles incluses dans JRE6 (Apache Commons n’est pas acceptable) et j’ai trouvé une solution simple en utilisant java.io.StreamTokenizer :

 import java.io.*; // ... Ssortingng literal = "\"Has \\\"\\\\\\\t\\\" & isn\\\'t \\\r\\\n on 1 line.\""; StreamTokenizer parser = new StreamTokenizer(new SsortingngReader(literal)); Ssortingng result; try { parser.nextToken(); if (parser.ttype == '"') { result = parser.sval; } else { result = "ERROR!"; } } catch (IOException e) { result = e.toSsortingng(); } System.out.println(result); 

Sortie:

 Has "\ " & isn't on 1 line. 

Voir ceci depuis http://commons.apache.org/lang/ :

SsortingngEscapeUtils

SsortingngEscapeUtils.unescapeJava(Ssortingng str)

Je suis un peu en retard à ce sujet, mais j’ai pensé que je fournirais ma solution car j’avais besoin des mêmes fonctionnalités. J’ai décidé d’utiliser l’API Java Comstackr, ce qui le ralentit, mais rend les résultats plus précis. Fondamentalement, je vis créer une classe puis retourner les résultats. Voici la méthode:

 public static Ssortingng[] unescapeJavaSsortingngs(Ssortingng... escaped) { //class name final Ssortingng className = "Temp" + System.currentTimeMillis(); //build the source final SsortingngBuilder source = new SsortingngBuilder(100 + escaped.length * 20). append("public class ").append(className).append("{\n"). append("\tpublic static Ssortingng[] getSsortingngs() {\n"). append("\t\treturn new Ssortingng[] {\n"); for (Ssortingng ssortingng : 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 && ssortingng.charAt(i - 1) != '\\') { source.append('\\'); } source.append(chr); } source.append("\",\n"); } source.append("\t\t};\n\t}\n}\n"); //obtain comstackr final JavaComstackr comstackr = ToolProvider.getSystemJavaComstackr(); //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("ssortingng:///" + 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("ssortingng:///" + 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( SsortingngUtils.class.getClassLoader(), new Class[] { JavaFileManager.class }, new InvocationHandler() { //standard file manager to delegate to private final JavaFileManager standard = comstackr.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 = comstackr.getTask(new OutputStreamWriter(err), fileManagerProxy, null, null, null, Collections.singleton(sourceFile)); //call it if (!task.call()) { throw new RuntimeException("Compilation failed, output:\n" + new Ssortingng(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(Ssortingng 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 (Ssortingng[]) clazz.getDeclaredMethod("getSsortingngs").invoke(null); } catch (Exception e) { throw new RuntimeException(e); } } 

Il faut un tableau pour pouvoir se dégager en lots. Ainsi, le test simple suivant réussit:

 public static void main(Ssortingng[] meh) { if ("1\02\03\n".equals(unescapeJavaSsortingngs("1\\02\\03\\n")[0])) { System.out.println("Success"); } else { System.out.println("Failure"); } } 

J’ai rencontré le même problème, mais aucune des solutions que j’ai trouvées ici ne m’a séduite. Donc, j’en ai écrit un qui parcourt les caractères de la chaîne en utilisant un matcher pour trouver et remplacer les séquences d’échappement. Cette solution suppose une entrée correctement formatée. Autrement dit, il saute avec bonheur les échappements absurdes et décode les échappements Unicode pour le saut de ligne et le retour chariot (qui ne peuvent pas apparaître dans un littéral de caractère ou un littéral de chaîne, en raison de la définition de ces littéraux et de l’ordre des phases de traduction pour Java). la source). Toutes mes excuses, le code est un peu emballé pour être bref.

 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.comstack("\\\\(?:(b|t|n|f|r|\\\"|\\\'|\\\\)|((?:[0-3]?[0-7])?[0-7])|u+(\\p{XDigit}{4}))"); public static CharSequence decodeSsortingng(CharSequence encodedSsortingng) { Matcher matcher = PATTERN.matcher(encodedSsortingng); SsortingngBuffer decodedSsortingng = new SsortingngBuffer(); // Find each escape of the encoded ssortingng 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(decodedSsortingng, Matcher.quoteReplacement(Ssortingng.valueOf(ch))); } // Append the remainder of the encoded ssortingng to the decoded ssortingng. // The remainder is the longest suffix of the encoded ssortingng such that the suffix contains no escapes. matcher.appendTail(decodedSsortingng); return decodedSsortingng; } public static void main(Ssortingng... args) { System.out.println(decodeSsortingng(args[0])); } } 

Je devrais noter que Apache Commons Lang3 ne semble pas souffrir des faiblesses indiquées dans la solution acceptée. C’est-à-dire que SsortingngEscapeUtils semble gérer les échappements octaux et les multiples caractères des échappements Unicode. Cela signifie que, à moins d’avoir de bonnes raisons d’éviter Apache Commons, vous devriez probablement l’utiliser plutôt que ma solution (ou toute autre solution ici).

Pour mémoire, si vous utilisez Scala, vous pouvez faire:

 SsortingngContext.treatEscapes(escaped) 

org.apache.commons.lang3.SsortingngEscapeUtils de commons-lang3 est maintenant obsolète. Vous pouvez utiliser org.apache.commons.text.SsortingngEscapeUtils#unescapeJava(Ssortingng) place. Il nécessite une dépendance Maven supplémentaire:

   org.apache.commons commons-text 1.4  

et semble traiter certains cas plus particuliers, par exemple:

  • échappements, citations simples et doubles
  • valeurs octales et unicodes échappées
  • \\b , \\n , \\t , \\f , \\r

Si vous lisez les caractères d’échappement d’unicode à partir d’un fichier, vous aurez du mal à le faire car la chaîne sera littéralement lue avec une échappée pour la barre oblique inverse:

mon_fichier.txt

 Blah blah... Column delimiter=; Word delimiter=\u0020 #This is just unicode for whitespace .. more stuff 

Ici, lorsque vous lisez la ligne 3 du fichier, la chaîne / ligne aura:

 "Word delimiter=\u0020 #This is just unicode for whitespace" 

et le caractère [] dans la chaîne affichera:

 {...., '=', '\\', 'u', '0', '0', '2', '0', ' ', '#', 't', 'h', ...} 

Commons SsortingngUnescape ne vous échappera pas (j’ai essayé unescapeXml ()). Vous devrez le faire manuellement comme décrit ici .

Ainsi, la sous-chaîne “\ u0020” devrait devenir 1 seul caractère ‘\ u0020’

Mais si vous utilisez ce “\ u0020” pour faire Ssortingng.split("... ..... ..", columnDelimiterReadFromFile) qui utilise vraiment regex en interne, il fonctionnera directement car la chaîne lue à partir du fichier a été échappée et est parfait pour utiliser dans le motif regex !! (Confus?)

Vous voudrez peut-être jeter un coup d’œil à l’implémentation Eclipse de Ssortingngliteral .