< prev index next >

src/java.base/share/classes/java/lang/String.java

Print this page
rev 51726 : 8202442: String::unescape
Reviewed-by: smarks, rriggs, sherman

@@ -2970,10 +2970,198 @@
                              .orElse(0);
         return indent(n - outdent, true);
     }
 
     /**
+     * Translates all Unicode escapes and escape sequences in this string into
+     * characters represented by those escapes specified in sections 3.3 and
+     * 3.10.6 of the <cite>The Java&trade; Language Specification</cite>.
+     * <p>
+     * Each unicode escape in the form \unnnn is translated to a
+     * 16-bit 'char' value.
+     * <p>
+     * Backslash escape sequences are translated as follows;
+     * <table class="plain">
+     *   <caption style="display:none">Escape sequences</caption>
+     *   <thead>
+     *   <tr>
+     *     <th scope="col">Escape</th>
+     *     <th scope="col">Name</th>
+     *     <th scope="col">Unicode</th>
+     *   </tr>
+     *   </thead>
+     *   <tr>
+     *     <td>{@code \b}</td>
+     *     <td>backspace</td>
+     *     <td>U+0008</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \t}</td>
+     *     <td>horizontal tab</td>
+     *     <td>U+0009</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \n}</td>
+     *     <td>line feed</td>
+     *     <td>U+000A</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \f}</td>
+     *     <td>form feed</td>
+     *     <td>U+000C</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \r}</td>
+     *     <td>carriage return</td>
+     *     <td>U+000D</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \"}</td>
+     *     <td>double quote</td>
+     *     <td>U+0022</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \'}</td>
+     *     <td>single quote</td>
+     *     <td>U+0027</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@code \\}</td>
+     *     <td>backslash</td>
+     *     <td>U+005C</td>
+     *   </tr>
+     * </table>
+     * <p>
+     * Octal escapes {@code \0 - \377} are translated to their code
+     * point equivalents.
+     *
+     * @return String with all escapes translated.
+     *
+     * @throws IllegalArgumentException when the escape sequence does
+     * not conform to JLS 3.3 or 3.10.6.
+     *
+     * @jls 3.3 Unicode escapes
+     * @jls 3.10.6 Escape sequences
+     *
+     * @since 12
+     *
+     * @deprecated  Preview feature associated with Raw String Literals.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    public String unescape() {
+        UnicodeReader reader = new UnicodeReader();
+        int length = reader.length();
+        char[] chars = new char[length];
+        int to = 0;
+        while (reader.hasNext()) {
+            char ch = reader.next();
+            if (ch == '\\') {
+                if (!reader.hasNext()) {
+                    reader.error("truncated escape sequence");
+                }
+                ch = reader.next();
+                switch (ch) {
+                    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;
+                    case '\"':
+                        ch = '\"';
+                        break;
+                    case '0': case '1': case '2': case '3':
+                    case '4': case '5': case '6': case '7':
+                        int code = ch - '0';
+                        for (int i = 0; i < 2 && reader.hasNext(); i++) {
+                            int digit = Character.digit(reader.next(), 8);
+                            if (digit < 0) {
+                                reader.pushBack();
+                                break;
+                            }
+                            code = code << 3 | digit;
+                        }
+                        if (0377 < code) {
+                            reader.error("octal escape sequence value is too large");
+                        }
+                        ch = (char)code;
+                        break;
+                    default:
+                        reader.error("unrecognized escape sequence");
+                }
+            }
+            chars[to++] = ch;
+        }
+        return new String(chars, 0, to);
+    }
+
+    private class UnicodeReader {
+        final int length;
+        int from;
+        int prev;
+
+        UnicodeReader() {
+            this.length = String.this.length();
+            this.from = 0;
+            this.prev = 0;
+        }
+
+        int length() {
+            return length;
+        }
+
+        boolean hasNext() {
+            return from < length;
+        }
+
+        char next() {
+            prev = from;
+            char next = charAt(from++);
+            if (next != '\\' || (hasNext() && charAt(from) != 'u')) {
+                return next;
+            }
+            do {
+                next = charAt(from++);
+            } while (next == 'u' && hasNext());
+            if (length <= from + 2) {
+                error("unicode escape sequence truncated at end of string");
+            }
+            int code = (Character.digit(next          , 16) << 12) |
+                       (Character.digit(charAt(from++), 16) <<  8) |
+                       (Character.digit(charAt(from++), 16) <<  4) |
+                        Character.digit(charAt(from++), 16);
+            if (code < 0) {
+                error("unicode escape sequence contains non hexadecimal digits");
+            }
+            return (char)code;
+        }
+
+        void pushBack() {
+            from = prev;
+        }
+
+        void error(String message) {
+            throw new IllegalArgumentException(message + ", pos = " + (from - 1));
+        }
+    }
+
+    /**
      * This object (which is already a string!) is itself returned.
      *
      * @return  the string itself.
      */
     public String toString() {
< prev index next >