如何在Java中使用Java字符串文字?

我正在使用Java处理一些Java源代码。 我正在提取字符串文字并将它们提供给一个带有String的函数。 问题是我需要将非转义版本的字符串传递给函数(即,这意味着将n转换为换行符, 转换为单个等)。

Java API中是否有这样的函数? 如果没有,我可以从某个图书馆获得这样的功能吗? 很显然,Java编译器必须进行这种转换。


PS - 如果有人想知道:我试图在反编译的混淆Java文件中混淆字符串文字


编辑:您可以下载我在下面讨论的功能的完整源代码 。 我也在这个答案中更详细地讨论它。

问题

这里给出的org.apache.commons.lang.StringEscapeUtils.unescapeJava()作为“答案”根本没有什么帮助。

  • 你必须提供装载另一个巨大的jar文件,用你不需要或想要的cruft的buttload。
  • 它有一个许可证。 有些人不想担心执照,不管它有多好或多糟。
  • 它忘记null的
  • 它不处理的八进制
  • 它不能处理java.util.regex.Pattern.compile()允许的各种转义以及使用它的所有转义,包括ae ,特别是cX
  • 它不支持数字逻辑Unicode代码点,只能用于愚蠢的UTF-16脑损伤。
  • 它是由一些血腥的白痴写的,他甚至不知道斜杠反斜杠之间的区别。
  • 源代码充满了恼人的回车。
  • 它被写为接受writer参数,所以如果你不通过它,它仍然需要为输出创建一个虚拟的StringWriter ,然后将其转换回给你。
  • 这看起来像UCS-2代码,而不是UTF-16代码:它们使用折旧的charAt接口而不是codePoint接口,因此公布了保证Java char保持Unicode字符的错觉。 不是。 他们只能逃避这种对星界飞机的盲目性,因为没有UTF-16替代品会结束寻找他们正在寻找的任何东西。
  • 像许多其他问题一样,他们对代码点U+2FU+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无知正则表达式透明转换为可以使用wWsSvV所有版本的版本, hHdDbBXR ,并让它们在Unicode中正常工作。 我所做的只是重写模式字符串; 它仍然使用标准的java.util.regex.Pattern.compile()函数进行编译,所以一切都按预期工作。 字符串unescaper故意通过任何b ,直到您调用转换器函数使Java正则表达式感知Unicode,因为它必须在边界意义上处理b

    无论如何,这里是字符串unescaper,尽管这两个字符串不那么有趣,但它确实解决了OP的问题,却没有对Apache代码的所有烦恼。 它可以在几个地方处理一些紧缩问题,但在午餐前几小时,我就迅速将其破解掉了,只是为了让它启动并运行来帮助驱动测试套件。 另一个功能是更多的工作:那个人昨天整整一天都带着我,为它补光。

    /*
     *
     * unescape_perl_string()
     *
     *      Tom Christiansen <tchrist@perl.com>
     *      Sun Nov 28 12:55:24 MST 2010
     *
     * It's completely ridiculous that there's no standard
     * unescape_java_string 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
     * strings:
     * 
     *   => "?" items  are additions to Java string 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, 12, x08 x{8}, u0008, U00000008
     *
     * Octal escapes:  N NN 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.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('07');
                           break; /* switch */
    
                case 'e':  newstr.append('33');
                           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  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是我最喜欢的语言。 恐怕我真的不得不在Rob Pike的这篇着名的公共静态空谈中站出来。

    “Nuff说。

    无论如何,这只是一个早上的骇人听闻,但如果它有助于其他人,欢迎您来到它 - 没有任何附加条件。 如果你改进它,我很乐意为你发送你的增强功能,但你当然不需要。


    您可以使用Apache Commons Lang的StringEscapeUtils String unescapeJava(String)方法。

    以下是一个示例代码片段:

        String in = "atbn"c"";
    
        System.out.println(in);
        // atbn"c"
    
        String out = StringEscapeUtils.unescapeJava(in);
    
        System.out.println(out);
        // a    b
        // "c"
    

    实用程序类具有用于Java,Java Script,HTML,XML和SQL的转义字符串和非字符串字符串的方法。 它也有直接写入java.io.Writer重载。


    注意事项

    它看起来像StringEscapeUtils处理Unicode一个逃脱u ,但不是八进制转义或Unicode与外来逃脱u秒。

        /* 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(
            "45"
        ); // %
        System.out.println(
            StringEscapeUtils.unescapeJava("45")
        ); // 45
        System.out.println(
            "45".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的一句名言:

    提供了八进制转义u00FF与C兼容,但只能表示Unicode值u0000u00FF ,因此Unicode转义u00FF通常是首选。

    如果您的字符串可以包含八进制转义符,您可能需要先将它们转换为Unicode转义符,或使用其他方法。

    无关的u也记录如下:

    Java编程语言规定了一种将用Unicode编写的程序转换为ASCII的标准方式,该程序将程序转换为可由基于ASCII的工具处理的格式。 转换包括通过添加一个额外的u将程序源文本中的所有Unicode转义转换为ASCII,例如uxxxx变为uuxxxx ,同时将源文本中的非ASCII字符转换为每个包含一个u的Unicode转义。

    这种转换后的版本对于Java编程语言的编译器同样可以接受,并且代表完全相同的程序。 确切的Unicode源以后可以从该ASCII形式通过转换多个其中每个转义序列恢复u的存在对的Unicode字符与序列少一个u ,同时用一个单一的转换每个转义序列u到相应的单个Unicode字符。

    如果您的字符串可能包含带有无关u Unicode转义符,那么您可能还需要在使用StringEscapeUtils之前对其进行预处理。

    或者,您可以尝试从头开始编写自己的Java字符串字符串,确保遵循确切的JLS规范。

    参考

  • JLS 3.3 Unicode转义
  • JLS 3.10.6用于字符和字符串文字的转义序列

  • 遇到类似的问题,不满意提出的解决方案,并自己实施这一个。

    也可作为Github上的Gist:

    /**
     * Unescapes a string that contains standard Java escape sequences.
     * <ul>
     * <li><strong>&#92;b &#92;f &#92;n &#92;r &#92;t &#92;" &#92;'</strong> :
     * BS, FF, NL, CR, TAB, double and single quote.</li>
     * <li><strong>&#92;X &#92;XX &#92;XXX</strong> : Octal character
     * specification (0 - 377, 0x00 - 0xFF).</li>
     * <li><strong>&#92;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://www.djcxy.com/p/47923.html

    上一篇: How to unescape a Java string literal in Java?

    下一篇: encode() escaping forward slashes