    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.io.IOException;
    020import java.io.Writer;
    021
    022import org.apache.commons.lang3.text.translate.AggregateTranslator;
    023import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
    024import org.apache.commons.lang3.text.translate.EntityArrays;
    025import org.apache.commons.lang3.text.translate.JavaUnicodeEscaper;
    026import org.apache.commons.lang3.text.translate.LookupTranslator;
    027import org.apache.commons.lang3.text.translate.NumericEntityEscaper;
    028import org.apache.commons.lang3.text.translate.NumericEntityUnescaper;
    029import org.apache.commons.lang3.text.translate.OctalUnescaper;
    030import org.apache.commons.lang3.text.translate.UnicodeUnescaper;
    031import org.apache.commons.lang3.text.translate.UnicodeUnpairedSurrogateRemover;
    032
    033/**
    034 * <p>Escapes and unescapes {@code String}s for
    035 * Java, Java Script, HTML and XML.</p>
    036 *
    037 * <p>#ThreadSafe#</p>
    038 * @since 2.0
    039 * @deprecated as of 3.6, use commons-text
    040 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringEscapeUtils.html">
    041 * StringEscapeUtils</a> instead
    042 */
    043@Deprecated
    044public class StringEscapeUtils {
    045
    046    /* ESCAPE TRANSLATORS */
    047
    048    /**
    049     * Translator object for escaping Java.
    050     *
    051     * While {@link #escapeJava(String)} is the expected method of use, this
    052     * object allows the Java escaping functionality to be used
    053     * as the foundation for a custom translator.
    054     *
    055     * @since 3.0
    056     */
    057    public static final CharSequenceTranslator ESCAPE_JAVA =
    058          new LookupTranslator(
    059            new String[][] {
    060              {"\"", "\\\""},
    061              {"\\", "\\\\"},
    062          }).with(
    063            new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE())
    064          ).with(
    065            JavaUnicodeEscaper.outsideOf(32, 0x7f)
    066        );
    067
    068    /**
    069     * Translator object for escaping EcmaScript/JavaScript.
    070     *
    071     * While {@link #escapeEcmaScript(String)} is the expected method of use, this
    072     * object allows the EcmaScript escaping functionality to be used
    073     * as the foundation for a custom translator.
    074     *
    075     * @since 3.0
    076     */
    077    public static final CharSequenceTranslator ESCAPE_ECMASCRIPT =
    078        new AggregateTranslator(
    079            new LookupTranslator(
    080                      new String[][] {
    081                            {"'", "\\'"},
    082                            {"\"", "\\\""},
    083                            {"\\", "\\\\"},
    084                            {"/", "\\/"}
    085                      }),
    086            new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()),
    087            JavaUnicodeEscaper.outsideOf(32, 0x7f)
    088        );
    089
    090    /**
    091     * Translator object for escaping Json.
    092     *
    093     * While {@link #escapeJson(String)} is the expected method of use, this
    094     * object allows the Json escaping functionality to be used
    095     * as the foundation for a custom translator.
    096     *
    097     * @since 3.2
    098     */
    099    public static final CharSequenceTranslator ESCAPE_JSON =
    100        new AggregateTranslator(
    101            new LookupTranslator(
    102                      new String[][] {
    103                            {"\"", "\\\""},
    104                            {"\\", "\\\\"},
    105                            {"/", "\\/"}
    106                      }),
    107            new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()),
    108            JavaUnicodeEscaper.outsideOf(32, 0x7f)
    109        );
    110
    111    /**
    112     * Translator object for escaping XML.
    113     *
    114     * While {@link #escapeXml(String)} is the expected method of use, this
    115     * object allows the XML escaping functionality to be used
    116     * as the foundation for a custom translator.
    117     *
    118     * @since 3.0
    119     * @deprecated use {@link #ESCAPE_XML10} or {@link #ESCAPE_XML11} instead.
    120     */
    121    @Deprecated
    122    public static final CharSequenceTranslator ESCAPE_XML =
    123        new AggregateTranslator(
    124            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
    125            new LookupTranslator(EntityArrays.APOS_ESCAPE())
    126        );
    127
    128    /**
    129     * Translator object for escaping XML 1.0.
    130     *
    131     * While {@link #escapeXml10(String)} is the expected method of use, this
    132     * object allows the XML escaping functionality to be used
    133     * as the foundation for a custom translator.
    134     *
    135     * @since 3.3
    136     */
    137    public static final CharSequenceTranslator ESCAPE_XML10 =
    138        new AggregateTranslator(
    139            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
    140            new LookupTranslator(EntityArrays.APOS_ESCAPE()),
    141            new LookupTranslator(
    142                    new String[][] {
    143                            { "\u0000", StringUtils.EMPTY },
    144                            { "\u0001", StringUtils.EMPTY },
    145                            { "\u0002", StringUtils.EMPTY },
    146                            { "\u0003", StringUtils.EMPTY },
    147                            { "\u0004", StringUtils.EMPTY },
    148                            { "\u0005", StringUtils.EMPTY },
    149                            { "\u0006", StringUtils.EMPTY },
    150                            { "\u0007", StringUtils.EMPTY },
    151                            { "\u0008", StringUtils.EMPTY },
    152                            { "\u000b", StringUtils.EMPTY },
    153                            { "\u000c", StringUtils.EMPTY },
    154                            { "\u000e", StringUtils.EMPTY },
    155                            { "\u000f", StringUtils.EMPTY },
    156                            { "\u0010", StringUtils.EMPTY },
    157                            { "\u0011", StringUtils.EMPTY },
    158                            { "\u0012", StringUtils.EMPTY },
    159                            { "\u0013", StringUtils.EMPTY },
    160                            { "\u0014", StringUtils.EMPTY },
    161                            { "\u0015", StringUtils.EMPTY },
    162                            { "\u0016", StringUtils.EMPTY },
    163                            { "\u0017", StringUtils.EMPTY },
    164                            { "\u0018", StringUtils.EMPTY },
    165                            { "\u0019", StringUtils.EMPTY },
    166                            { "\u001a", StringUtils.EMPTY },
    167                            { "\u001b", StringUtils.EMPTY },
    168                            { "\u001c", StringUtils.EMPTY },
    169                            { "\u001d", StringUtils.EMPTY },
    170                            { "\u001e", StringUtils.EMPTY },
    171                            { "\u001f", StringUtils.EMPTY },
    172                            { "\ufffe", StringUtils.EMPTY },
    173                            { "\uffff", StringUtils.EMPTY }
    174                    }),
    175            NumericEntityEscaper.between(0x7f, 0x84),
    176            NumericEntityEscaper.between(0x86, 0x9f),
    177            new UnicodeUnpairedSurrogateRemover()
    178        );
    179
    180    /**
    181     * Translator object for escaping XML 1.1.
    182     *
    183     * While {@link #escapeXml11(String)} is the expected method of use, this
    184     * object allows the XML escaping functionality to be used
    185     * as the foundation for a custom translator.
    186     *
    187     * @since 3.3
    188     */
    189    public static final CharSequenceTranslator ESCAPE_XML11 =
    190        new AggregateTranslator(
    191            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
    192            new LookupTranslator(EntityArrays.APOS_ESCAPE()),
    193            new LookupTranslator(
    194                    new String[][] {
    195                            { "\u0000", StringUtils.EMPTY },
    196                            { "\u000b", "&#11;" },
    197                            { "\u000c", "&#12;" },
    198                            { "\ufffe", StringUtils.EMPTY },
    199                            { "\uffff", StringUtils.EMPTY }
    200                    }),
    201            NumericEntityEscaper.between(0x1, 0x8),
    202            NumericEntityEscaper.between(0xe, 0x1f),
    203            NumericEntityEscaper.between(0x7f, 0x84),
    204            NumericEntityEscaper.between(0x86, 0x9f),
    205            new UnicodeUnpairedSurrogateRemover()
    206        );
    207
    208    /**
    209     * Translator object for escaping HTML version 3.0.
    210     *
    211     * While {@link #escapeHtml3(String)} is the expected method of use, this
    212     * object allows the HTML escaping functionality to be used
    213     * as the foundation for a custom translator.
    214     *
    215     * @since 3.0
    216     */
    217    public static final CharSequenceTranslator ESCAPE_HTML3 =
    218        new AggregateTranslator(
    219            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
    220            new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE())
    221        );
    222
    223    /**
    224     * Translator object for escaping HTML version 4.0.
    225     *
    226     * While {@link #escapeHtml4(String)} is the expected method of use, this
    227     * object allows the HTML escaping functionality to be used
    228     * as the foundation for a custom translator.
    229     *
    230     * @since 3.0
    231     */
    232    public static final CharSequenceTranslator ESCAPE_HTML4 =
    233        new AggregateTranslator(
    234            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
    235            new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()),
    236            new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE())
    237        );
    238
    239    /**
    240     * Translator object for escaping individual Comma Separated Values.
    241     *
    242     * While {@link #escapeCsv(String)} is the expected method of use, this
    243     * object allows the CSV escaping functionality to be used
    244     * as the foundation for a custom translator.
    245     *
    246     * @since 3.0
    247     */
    248    public static final CharSequenceTranslator ESCAPE_CSV = new CsvEscaper();
    249
    250    // TODO: Create a parent class - 'SinglePassTranslator' ?
    251    //       It would handle the index checking + length returning,
    252    //       and could also have an optimization check method.
    253    static class CsvEscaper extends CharSequenceTranslator {
    254
    255        private static final char CSV_DELIMITER = ',';
    256        private static final char CSV_QUOTE = '"';
    257        private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
    258        private static final char[] CSV_SEARCH_CHARS = { CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF };
    259
    260        @Override
    261        public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
    262
    263            if (index != 0) {
    264                throw new IllegalStateException("CsvEscaper should never reach the [1] index");
    265            }
    266
    267            if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) {
    268                out.write(input.toString());
    269            } else {
    270                out.write(CSV_QUOTE);
    271                out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR));
    272                out.write(CSV_QUOTE);
    273            }
    274            return Character.codePointCount(input, 0, input.length());
    275        }
    276    }
    277
    278    /* UNESCAPE TRANSLATORS */
    279
    280    /**
    281     * Translator object for unescaping escaped Java.
    282     *
    283     * While {@link #unescapeJava(String)} is the expected method of use, this
    284     * object allows the Java unescaping functionality to be used
    285     * as the foundation for a custom translator.
    286     *
    287     * @since 3.0
    288     */
    289    // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)?
    290    public static final CharSequenceTranslator UNESCAPE_JAVA =
    291        new AggregateTranslator(
    292            new OctalUnescaper(),     // .between('\1', '\377'),
    293            new UnicodeUnescaper(),
    294            new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE()),
    295            new LookupTranslator(
    296                      new String[][] {
    297                            {"\\\\", "\\"},
    298                            {"\\\"", "\""},
    299                            {"\\'", "'"},
    300                            {"\\", ""}
    301                      })
    302        );
    303
    304    /**
    305     * Translator object for unescaping escaped EcmaScript.
    306     *
    307     * While {@link #unescapeEcmaScript(String)} is the expected method of use, this
    308     * object allows the EcmaScript unescaping functionality to be used
    309     * as the foundation for a custom translator.
    310     *
    311     * @since 3.0
    312     */
    313    public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA;
    314
    315    /**
    316     * Translator object for unescaping escaped Json.
    317     *
    318     * While {@link #unescapeJson(String)} is the expected method of use, this
    319     * object allows the Json unescaping functionality to be used
    320     * as the foundation for a custom translator.
    321     *
    322     * @since 3.2
    323     */
    324    public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA;
    325
    326    /**
    327     * Translator object for unescaping escaped HTML 3.0.
    328     *
    329     * While {@link #unescapeHtml3(String)} is the expected method of use, this
    330     * object allows the HTML unescaping functionality to be used
    331     * as the foundation for a custom translator.
    332     *
    333     * @since 3.0
    334     */
    335    public static final CharSequenceTranslator UNESCAPE_HTML3 =
    336        new AggregateTranslator(
    337            new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
    338            new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()),
    339            new NumericEntityUnescaper()
    340        );
    341
    342    /**
    343     * Translator object for unescaping escaped HTML 4.0.
    344     *
    345     * While {@link #unescapeHtml4(String)} is the expected method of use, this
    346     * object allows the HTML unescaping functionality to be used
    347     * as the foundation for a custom translator.
    348     *
    349     * @since 3.0
    350     */
    351    public static final CharSequenceTranslator UNESCAPE_HTML4 =
    352        new AggregateTranslator(
    353            new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
    354            new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()),
    355            new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE()),
    356            new NumericEntityUnescaper()
    357        );
    358
    359    /**
    360     * Translator object for unescaping escaped XML.
    361     *
    362     * While {@link #unescapeXml(String)} is the expected method of use, this
    363     * object allows the XML unescaping functionality to be used
    364     * as the foundation for a custom translator.
    365     *
    366     * @since 3.0
    367     */
    368    public static final CharSequenceTranslator UNESCAPE_XML =
    369        new AggregateTranslator(
    370            new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
    371            new LookupTranslator(EntityArrays.APOS_UNESCAPE()),
    372            new NumericEntityUnescaper()
    373        );
    374
    375    /**
    376     * Translator object for unescaping escaped Comma Separated Value entries.
    377     *
    378     * While {@link #unescapeCsv(String)} is the expected method of use, this
    379     * object allows the CSV unescaping functionality to be used
    380     * as the foundation for a custom translator.
    381     *
    382     * @since 3.0
    383     */
    384    public static final CharSequenceTranslator UNESCAPE_CSV = new CsvUnescaper();
    385
    386    static class CsvUnescaper extends CharSequenceTranslator {
    387
    388        private static final char CSV_DELIMITER = ',';
    389        private static final char CSV_QUOTE = '"';
    390        private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
    391        private static final char[] CSV_SEARCH_CHARS = {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
    392
    393        @Override
    394        public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
    395
    396            if (index != 0) {
    397                throw new IllegalStateException("CsvUnescaper should never reach the [1] index");
    398            }
    399
    400            if ( input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE ) {
    401                out.write(input.toString());
    402                return Character.codePointCount(input, 0, input.length());
    403            }
    404
    405            // strip quotes
    406            final String quoteless = input.subSequence(1, input.length() - 1).toString();
    407
    408            if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) {
    409                // deal with escaped quotes; ie) ""
    410                out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR));
    411            } else {
    412                out.write(input.toString());
    413            }
    414            return Character.codePointCount(input, 0, input.length());
    415        }
    416    }
    417
    418    /* Helper functions */
    419
    420    /**
    421     * <p>{@code StringEscapeUtils} instances should NOT be constructed in
    422     * standard programming.</p>
    423     *
    424     * <p>Instead, the class should be used as:</p>
    425     * <pre>StringEscapeUtils.escapeJava("foo");</pre>
    426     *
    427     * <p>This constructor is public to permit tools that require a JavaBean
    428     * instance to operate.</p>
    429     */
    430    public StringEscapeUtils() {
    431      super();
    432    }
    433
    434    // Java and JavaScript
    435    //--------------------------------------------------------------------------
    436    /**
    437     * <p>Escapes the characters in a {@code String} using Java String rules.</p>
    438     *
    439     * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
    440     *
    441     * <p>So a tab becomes the characters {@code '\\'} and
    442     * {@code 't'}.</p>
    443     *
    444     * <p>The only difference between Java strings and JavaScript strings
    445     * is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
    446     *
    447     * <p>Example:</p>
    448     * <pre>
    449     * input string: He didn't say, "Stop!"
    450     * output string: He didn't say, \"Stop!\"
    451     * </pre>
    452     *
    453     * @param input  String to escape values in, may be null
    454     * @return String with escaped values, {@code null} if null string input
    455     */
    456    public static final String escapeJava(final String input) {
    457        return ESCAPE_JAVA.translate(input);
    458    }
    459
    460    /**
    461     * <p>Escapes the characters in a {@code String} using EcmaScript String rules.</p>
    462     * <p>Escapes any values it finds into their EcmaScript String form.
    463     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
    464     *
    465     * <p>So a tab becomes the characters {@code '\\'} and
    466     * {@code 't'}.</p>
    467     *
    468     * <p>The only difference between Java strings and EcmaScript strings
    469     * is that in EcmaScript, a single quote and forward-slash (/) are escaped.</p>
    470     *
    471     * <p>Note that EcmaScript is best known by the JavaScript and ActionScript dialects. </p>
    472     *
    473     * <p>Example:</p>
    474     * <pre>
    475     * input string: He didn't say, "Stop!"
    476     * output string: He didn\'t say, \"Stop!\"
    477     * </pre>
    478     *
    479     * @param input  String to escape values in, may be null
    480     * @return String with escaped values, {@code null} if null string input
    481     *
    482     * @since 3.0
    483     */
    484    public static final String escapeEcmaScript(final String input) {
    485        return ESCAPE_ECMASCRIPT.translate(input);
    486    }
    487
    488    /**
    489     * <p>Escapes the characters in a {@code String} using Json String rules.</p>
    490     * <p>Escapes any values it finds into their Json String form.
    491     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
    492     *
    493     * <p>So a tab becomes the characters {@code '\\'} and
    494     * {@code 't'}.</p>
    495     *
    496     * <p>The only difference between Java strings and Json strings
    497     * is that in Json, forward-slash (/) is escaped.</p>
    498     *
    499     * <p>See http://www.ietf.org/rfc/rfc4627.txt for further details. </p>
    500     *
    501     * <p>Example:</p>
    502     * <pre>
    503     * input string: He didn't say, "Stop!"
    504     * output string: He didn't say, \"Stop!\"
    505     * </pre>
    506     *
    507     * @param input  String to escape values in, may be null
    508     * @return String with escaped values, {@code null} if null string input
    509     *
    510     * @since 3.2
    511     */
    512    public static final String escapeJson(final String input) {
    513        return ESCAPE_JSON.translate(input);
    514    }
    515
    516    /**
    517     * <p>Unescapes any Java literals found in the {@code String}.
    518     * For example, it will turn a sequence of {@code '\'} and
    519     * {@code 'n'} into a newline character, unless the {@code '\'}
    520     * is preceded by another {@code '\'}.</p>
    521     *
    522     * @param input  the {@code String} to unescape, may be null
    523     * @return a new unescaped {@code String}, {@code null} if null string input
    524     */
    525    public static final String unescapeJava(final String input) {
    526        return UNESCAPE_JAVA.translate(input);
    527    }
    528
    529    /**
    530     * <p>Unescapes any EcmaScript literals found in the {@code String}.</p>
    531     *
    532     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
    533     * into a newline character, unless the {@code '\'} is preceded by another
    534     * {@code '\'}.</p>
    535     *
    536     * @see #unescapeJava(String)
    537     * @param input  the {@code String} to unescape, may be null
    538     * @return A new unescaped {@code String}, {@code null} if null string input
    539     *
    540     * @since 3.0
    541     */
    542    public static final String unescapeEcmaScript(final String input) {
    543        return UNESCAPE_ECMASCRIPT.translate(input);
    544    }
    545
    546    /**
    547     * <p>Unescapes any Json literals found in the {@code String}.</p>
    548     *
    549     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
    550     * into a newline character, unless the {@code '\'} is preceded by another
    551     * {@code '\'}.</p>
    552     *
    553     * @see #unescapeJava(String)
    554     * @param input  the {@code String} to unescape, may be null
    555     * @return A new unescaped {@code String}, {@code null} if null string input
    556     *
    557     * @since 3.2
    558     */
    559    public static final String unescapeJson(final String input) {
    560        return UNESCAPE_JSON.translate(input);
    561    }
    562
    563    // HTML and XML
    564    //--------------------------------------------------------------------------
    565    /**
    566     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
    567     *
    568     * <p>
    569     * For example:
    570     * </p>
    571     * <p>{@code "bread" &amp; "butter"}</p>
    572     * becomes:
    573     * <p>
    574     * {@code &amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;}.
    575     * </p>
    576     *
    577     * <p>Supports all known HTML 4.0 entities, including funky accents.
    578     * Note that the commonly used apostrophe escape character (&amp;apos;)
    579     * is not a legal entity and so is not supported). </p>
    580     *
    581     * @param input  the {@code String} to escape, may be null
    582     * @return a new escaped {@code String}, {@code null} if null string input
    583     *
    584     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
    585     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
    586     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
    587     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
    588     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
    589     *
    590     * @since 3.0
    591     */
    592    public static final String escapeHtml4(final String input) {
    593        return ESCAPE_HTML4.translate(input);
    594    }
    595
    596    /**
    597     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
    598     * <p>Supports only the HTML 3.0 entities. </p>
    599     *
    600     * @param input  the {@code String} to escape, may be null
    601     * @return a new escaped {@code String}, {@code null} if null string input
    602     *
    603     * @since 3.0
    604     */
    605    public static final String escapeHtml3(final String input) {
    606        return ESCAPE_HTML3.translate(input);
    607    }
    608
    609    //-----------------------------------------------------------------------
    610    /**
    611     * <p>Unescapes a string containing entity escapes to a string
    612     * containing the actual Unicode characters corresponding to the
    613     * escapes. Supports HTML 4.0 entities.</p>
    614     *
    615     * <p>For example, the string {@code "&lt;Fran&ccedil;ais&gt;"}
    616     * will become {@code "<Français>"}</p>
    617     *
    618     * <p>If an entity is unrecognized, it is left alone, and inserted
    619     * verbatim into the result string. e.g. {@code "&gt;&zzzz;x"} will
    620     * become {@code ">&zzzz;x"}.</p>
    621     *
    622     * @param input  the {@code String} to unescape, may be null
    623     * @return a new unescaped {@code String}, {@code null} if null string input
    624     *
    625     * @since 3.0
    626     */
    627    public static final String unescapeHtml4(final String input) {
    628        return UNESCAPE_HTML4.translate(input);
    629    }
    630
    631    /**
    632     * <p>Unescapes a string containing entity escapes to a string
    633     * containing the actual Unicode characters corresponding to the
    634     * escapes. Supports only HTML 3.0 entities.</p>
    635     *
    636     * @param input  the {@code String} to unescape, may be null
    637     * @return a new unescaped {@code String}, {@code null} if null string input
    638     *
    639     * @since 3.0
    640     */
    641    public static final String unescapeHtml3(final String input) {
    642        return UNESCAPE_HTML3.translate(input);
    643    }
    644
    645    //-----------------------------------------------------------------------
    646    /**
    647     * <p>Escapes the characters in a {@code String} using XML entities.</p>
    648     *
    649     * <p>For example: {@code "bread" & "butter"} =&gt;
    650     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
    651     * </p>
    652     *
    653     * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
    654     * Does not support DTDs or external entities.</p>
    655     *
    656     * <p>Note that Unicode characters greater than 0x7f are as of 3.0, no longer
    657     *    escaped. If you still wish this functionality, you can achieve it
    658     *    via the following:
    659     * {@code StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );}</p>
    660     *
    661     * @param input  the {@code String} to escape, may be null
    662     * @return a new escaped {@code String}, {@code null} if null string input
    663     * @see #unescapeXml(java.lang.String)
    664     * @deprecated use {@link #escapeXml10(java.lang.String)} or {@link #escapeXml11(java.lang.String)} instead.
    665     */
    666    @Deprecated
    667    public static final String escapeXml(final String input) {
    668        return ESCAPE_XML.translate(input);
    669    }
    670
    671    /**
    672     * <p>Escapes the characters in a {@code String} using XML entities.</p>
    673     *
    674     * <p>For example: {@code "bread" & "butter"} =&gt;
    675     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
    676     * </p>
    677     *
    678     * <p>Note that XML 1.0 is a text-only format: it cannot represent control
    679     * characters or unpaired Unicode surrogate codepoints, even after escaping.
    680     * {@code escapeXml10} will remove characters that do not fit in the
    681     * following ranges:</p>
    682     *
    683     * <p>{@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
    684     *
    685     * <p>Though not strictly necessary, {@code escapeXml10} will escape
    686     * characters in the following ranges:</p>
    687     *
    688     * <p>{@code [#x7F-#x84] | [#x86-#x9F]}</p>
    689     *
    690     * <p>The returned string can be inserted into a valid XML 1.0 or XML 1.1
    691     * document. If you want to allow more non-text characters in an XML 1.1
    692     * document, use {@link #escapeXml11(String)}.</p>
    693     *
    694     * @param input  the {@code String} to escape, may be null
    695     * @return a new escaped {@code String}, {@code null} if null string input
    696     * @see #unescapeXml(java.lang.String)
    697     * @since 3.3
    698     */
    699    public static String escapeXml10(final String input) {
    700        return ESCAPE_XML10.translate(input);
    701    }
    702
    703    /**
    704     * <p>Escapes the characters in a {@code String} using XML entities.</p>
    705     *
    706     * <p>For example: {@code "bread" & "butter"} =&gt;
    707     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
    708     * </p>
    709     *
    710     * <p>XML 1.1 can represent certain control characters, but it cannot represent
    711     * the null byte or unpaired Unicode surrogate codepoints, even after escaping.
    712     * {@code escapeXml11} will remove characters that do not fit in the following
    713     * ranges:</p>
    714     *
    715     * <p>{@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
    716     *
    717     * <p>{@code escapeXml11} will escape characters in the following ranges:</p>
    718     *
    719     * <p>{@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]}</p>
    720     *
    721     * <p>The returned string can be inserted into a valid XML 1.1 document. Do not
    722     * use it for XML 1.0 documents.</p>
    723     *
    724     * @param input  the {@code String} to escape, may be null
    725     * @return a new escaped {@code String}, {@code null} if null string input
    726     * @see #unescapeXml(java.lang.String)
    727     * @since 3.3
    728     */
    729    public static String escapeXml11(final String input) {
    730        return ESCAPE_XML11.translate(input);
    731    }
    732
    733    //-----------------------------------------------------------------------
    734    /**
    735     * <p>Unescapes a string containing XML entity escapes to a string
    736     * containing the actual Unicode characters corresponding to the
    737     * escapes.</p>
    738     *
    739     * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
    740     * Does not support DTDs or external entities.</p>
    741     *
    742     * <p>Note that numerical \\u Unicode codes are unescaped to their respective
    743     *    Unicode characters. This may change in future releases. </p>
    744     *
    745     * @param input  the {@code String} to unescape, may be null
    746     * @return a new unescaped {@code String}, {@code null} if null string input
    747     * @see #escapeXml(String)
    748     * @see #escapeXml10(String)
    749     * @see #escapeXml11(String)
    750     */
    751    public static final String unescapeXml(final String input) {
    752        return UNESCAPE_XML.translate(input);
    753    }
    754
    755    //-----------------------------------------------------------------------
    756
    757    /**
    758     * <p>Returns a {@code String} value for a CSV column enclosed in double quotes,
    759     * if required.</p>
    760     *
    761     * <p>If the value contains a comma, newline or double quote, then the
    762     *    String value is returned enclosed in double quotes.</p>
    763     *
    764     * <p>Any double quote characters in the value are escaped with another double quote.</p>
    765     *
    766     * <p>If the value does not contain a comma, newline or double quote, then the
    767     *    String value is returned unchanged.</p>
    768     *
    769     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
    770     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
    771     *
    772     * @param input the input CSV column String, may be null
    773     * @return the input String, enclosed in double quotes if the value contains a comma,
    774     * newline or double quote, {@code null} if null string input
    775     * @since 2.4
    776     */
    777    public static final String escapeCsv(final String input) {
    778        return ESCAPE_CSV.translate(input);
    779    }
    780
    781    /**
    782     * <p>Returns a {@code String} value for an unescaped CSV column. </p>
    783     *
    784     * <p>If the value is enclosed in double quotes, and contains a comma, newline
    785     *    or double quote, then quotes are removed.
    786     * </p>
    787     *
    788     * <p>Any double quote escaped characters (a pair of double quotes) are unescaped
    789     *    to just one double quote. </p>
    790     *
    791     * <p>If the value is not enclosed in double quotes, or is and does not contain a
    792     *    comma, newline or double quote, then the String value is returned unchanged.</p>
    793     *
    794     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
    795     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
    796     *
    797     * @param input the input CSV column String, may be null
    798     * @return the input String, with enclosing double quotes removed and embedded double
    799     * quotes unescaped, {@code null} if null string input
    800     * @since 2.4
    801     */
    802    public static final String unescapeCsv(final String input) {
    803        return UNESCAPE_CSV.translate(input);
    804    }
    805
    806}