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 *      https://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.text;
018
019import java.io.IOException;
020import java.io.Writer;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024
025import org.apache.commons.lang3.StringUtils;
026import org.apache.commons.text.translate.AggregateTranslator;
027import org.apache.commons.text.translate.CharSequenceTranslator;
028import org.apache.commons.text.translate.CsvTranslators;
029import org.apache.commons.text.translate.EntityArrays;
030import org.apache.commons.text.translate.JavaUnicodeEscaper;
031import org.apache.commons.text.translate.LookupTranslator;
032import org.apache.commons.text.translate.NumericEntityEscaper;
033import org.apache.commons.text.translate.NumericEntityUnescaper;
034import org.apache.commons.text.translate.OctalUnescaper;
035import org.apache.commons.text.translate.UnicodeUnescaper;
036import org.apache.commons.text.translate.UnicodeUnpairedSurrogateRemover;
037
038/**
039 * <p>
040 * Escapes and unescapes {@code String}s for Java, Java Script, HTML and XML.
041 * </p>
042 *
043 * <p>
044 * #ThreadSafe#
045 * </p>
046 *
047 * <p>
048 * This code has been adapted from Apache Commons Lang 3.5.
049 * </p>
050 *
051 * @since 1.0
052 */
053public class StringEscapeUtils {
054
055    /* ESCAPE TRANSLATORS */
056
057    /**
058     * Convenience wrapper for {@link StringBuilder} providing escape methods.
059     *
060     * <p>Example:</p>
061     * <pre>
062     * new Builder(ESCAPE_HTML4)
063     *      .append("&lt;p&gt;")
064     *      .escape("This is paragraph 1 and special chars like &amp; get escaped.")
065     *      .append("&lt;/p&gt;&lt;p&gt;")
066     *      .escape("This is paragraph 2 &amp; more...")
067     *      .append("&lt;/p&gt;")
068     *      .toString()
069     * </pre>
070     */
071    public static final class Builder {
072
073        /**
074         * StringBuilder to be used in the Builder class.
075         */
076        private final StringBuilder sb;
077
078        /**
079         * CharSequenceTranslator to be used in the Builder class.
080         */
081        private final CharSequenceTranslator translator;
082
083        /**
084         * Builder constructor.
085         *
086         * @param translator a CharSequenceTranslator.
087         */
088        private Builder(final CharSequenceTranslator translator) {
089            this.sb = new StringBuilder();
090            this.translator = translator;
091        }
092
093        /**
094         * Literal append, no escaping being done.
095         *
096         * @param input the String to append
097         * @return {@code this}, to enable chaining
098         */
099        public Builder append(final String input) {
100            sb.append(input);
101            return this;
102        }
103
104        /**
105         * Escape {@code input} according to the given {@link CharSequenceTranslator}.
106         *
107         * @param input the String to escape
108         * @return {@code this}, to enable chaining
109         */
110        public Builder escape(final String input) {
111            sb.append(translator.translate(input));
112            return this;
113        }
114
115        /**
116         * Return the escaped string.
117         *
118         * @return The escaped string
119         */
120        @Override
121        public String toString() {
122            return sb.toString();
123        }
124    }
125    /**
126     * Translator object for unescaping backslash escaped entries.
127     */
128    static class XsiUnescaper extends CharSequenceTranslator {
129
130        /**
131         * Escaped backslash constant.
132         */
133        private static final char BACKSLASH = '\\';
134
135        @Override
136        public int translate(final CharSequence input, final int index, final Writer writer) throws IOException {
137
138            if (index != 0) {
139                throw new IllegalStateException("XsiUnescaper should never reach the [1] index");
140            }
141
142            final String s = input.toString();
143
144            int segmentStart = 0;
145            int searchOffset = 0;
146            while (true) {
147                final int pos = s.indexOf(BACKSLASH, searchOffset);
148                if (pos == -1) {
149                    if (segmentStart < s.length()) {
150                        writer.write(s.substring(segmentStart));
151                    }
152                    break;
153                }
154                if (pos > segmentStart) {
155                    writer.write(s.substring(segmentStart, pos));
156                }
157                segmentStart = pos + 1;
158                searchOffset = pos + 2;
159            }
160
161            return Character.codePointCount(input, 0, input.length());
162        }
163    }
164
165    /**
166     * Translator object for escaping Java.
167     *
168     * While {@link #escapeJava(String)} is the expected method of use, this object allows the Java escaping functionality to be used as the foundation for a
169     * custom translator.
170     */
171    public static final CharSequenceTranslator ESCAPE_JAVA;
172    static {
173        final Map<CharSequence, CharSequence> escapeJavaMap = new HashMap<>();
174        escapeJavaMap.put("\"", "\\\"");
175        escapeJavaMap.put("\\", "\\\\");
176        ESCAPE_JAVA = new AggregateTranslator(
177                new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)),
178                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
179                JavaUnicodeEscaper.outsideOf(32, 0x7f)
180        );
181    }
182
183    /**
184     * Translator object for escaping EcmaScript/JavaScript.
185     *
186     * While {@link #escapeEcmaScript(String)} is the expected method of use, this object allows the EcmaScript escaping functionality to be used as the
187     * foundation for a custom translator.
188     */
189    public static final CharSequenceTranslator ESCAPE_ECMASCRIPT;
190    static {
191        final Map<CharSequence, CharSequence> escapeEcmaScriptMap = new HashMap<>();
192        escapeEcmaScriptMap.put("'", "\\'");
193        escapeEcmaScriptMap.put("\"", "\\\"");
194        escapeEcmaScriptMap.put("\\", "\\\\");
195        escapeEcmaScriptMap.put("/", "\\/");
196        ESCAPE_ECMASCRIPT = new AggregateTranslator(
197                new LookupTranslator(Collections.unmodifiableMap(escapeEcmaScriptMap)),
198                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
199                JavaUnicodeEscaper.outsideOf(32, 0x7f)
200        );
201    }
202
203    /**
204     * Translator object for escaping Json.
205     *
206     * While {@link #escapeJson(String)} is the expected method of use, this object allows the Json escaping functionality to be used as the foundation for a
207     * custom translator.
208     */
209    public static final CharSequenceTranslator ESCAPE_JSON;
210    static {
211        final Map<CharSequence, CharSequence> escapeJsonMap = new HashMap<>();
212        escapeJsonMap.put("\"", "\\\"");
213        escapeJsonMap.put("\\", "\\\\");
214        escapeJsonMap.put("/", "\\/");
215        ESCAPE_JSON = new AggregateTranslator(
216                new LookupTranslator(Collections.unmodifiableMap(escapeJsonMap)),
217                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
218                JavaUnicodeEscaper.outsideOf(32, 0x7e)
219        );
220    }
221
222    /**
223     * Translator object for escaping XML 1.0.
224     *
225     * While {@link #escapeXml10(String)} is the expected method of use, this object allows the XML escaping functionality to be used as the foundation for a
226     * custom translator.
227     */
228    public static final CharSequenceTranslator ESCAPE_XML10;
229    static {
230        final Map<CharSequence, CharSequence> escapeXml10Map = new HashMap<>();
231        escapeXml10Map.put("\u0000", StringUtils.EMPTY);
232        escapeXml10Map.put("\u0001", StringUtils.EMPTY);
233        escapeXml10Map.put("\u0002", StringUtils.EMPTY);
234        escapeXml10Map.put("\u0003", StringUtils.EMPTY);
235        escapeXml10Map.put("\u0004", StringUtils.EMPTY);
236        escapeXml10Map.put("\u0005", StringUtils.EMPTY);
237        escapeXml10Map.put("\u0006", StringUtils.EMPTY);
238        escapeXml10Map.put("\u0007", StringUtils.EMPTY);
239        escapeXml10Map.put("\u0008", StringUtils.EMPTY);
240        escapeXml10Map.put("\u000b", StringUtils.EMPTY);
241        escapeXml10Map.put("\u000c", StringUtils.EMPTY);
242        escapeXml10Map.put("\u000e", StringUtils.EMPTY);
243        escapeXml10Map.put("\u000f", StringUtils.EMPTY);
244        escapeXml10Map.put("\u0010", StringUtils.EMPTY);
245        escapeXml10Map.put("\u0011", StringUtils.EMPTY);
246        escapeXml10Map.put("\u0012", StringUtils.EMPTY);
247        escapeXml10Map.put("\u0013", StringUtils.EMPTY);
248        escapeXml10Map.put("\u0014", StringUtils.EMPTY);
249        escapeXml10Map.put("\u0015", StringUtils.EMPTY);
250        escapeXml10Map.put("\u0016", StringUtils.EMPTY);
251        escapeXml10Map.put("\u0017", StringUtils.EMPTY);
252        escapeXml10Map.put("\u0018", StringUtils.EMPTY);
253        escapeXml10Map.put("\u0019", StringUtils.EMPTY);
254        escapeXml10Map.put("\u001a", StringUtils.EMPTY);
255        escapeXml10Map.put("\u001b", StringUtils.EMPTY);
256        escapeXml10Map.put("\u001c", StringUtils.EMPTY);
257        escapeXml10Map.put("\u001d", StringUtils.EMPTY);
258        escapeXml10Map.put("\u001e", StringUtils.EMPTY);
259        escapeXml10Map.put("\u001f", StringUtils.EMPTY);
260        escapeXml10Map.put("\ufffe", StringUtils.EMPTY);
261        escapeXml10Map.put("\uffff", StringUtils.EMPTY);
262        ESCAPE_XML10 = new AggregateTranslator(
263                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
264                new LookupTranslator(EntityArrays.APOS_ESCAPE),
265                new LookupTranslator(Collections.unmodifiableMap(escapeXml10Map)),
266                NumericEntityEscaper.between(0x7f, 0x84),
267                NumericEntityEscaper.between(0x86, 0x9f),
268                new UnicodeUnpairedSurrogateRemover()
269        );
270    }
271
272    /**
273     * Translator object for escaping XML 1.1.
274     *
275     * While {@link #escapeXml11(String)} is the expected method of use, this
276     * object allows the XML escaping functionality to be used
277     * as the foundation for a custom translator.
278     */
279    public static final CharSequenceTranslator ESCAPE_XML11;
280
281    static {
282        final Map<CharSequence, CharSequence> escapeXml11Map = new HashMap<>();
283        escapeXml11Map.put("\u0000", StringUtils.EMPTY);
284        escapeXml11Map.put("\u000b", "&#11;");
285        escapeXml11Map.put("\u000c", "&#12;");
286        escapeXml11Map.put("\ufffe", StringUtils.EMPTY);
287        escapeXml11Map.put("\uffff", StringUtils.EMPTY);
288        ESCAPE_XML11 = new AggregateTranslator(
289                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
290                new LookupTranslator(EntityArrays.APOS_ESCAPE),
291                new LookupTranslator(Collections.unmodifiableMap(escapeXml11Map)),
292                NumericEntityEscaper.between(0x1, 0x8),
293                NumericEntityEscaper.between(0xe, 0x1f),
294                NumericEntityEscaper.between(0x7f, 0x84),
295                NumericEntityEscaper.between(0x86, 0x9f),
296                new UnicodeUnpairedSurrogateRemover()
297        );
298    }
299
300    /**
301     * Translator object for escaping HTML version 3.0.
302     *
303     * While {@link #escapeHtml3(String)} is the expected method of use, this
304     * object allows the HTML escaping functionality to be used
305     * as the foundation for a custom translator.
306     */
307    public static final CharSequenceTranslator ESCAPE_HTML3 =
308            new AggregateTranslator(
309                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
310                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE)
311            );
312
313    /**
314     * Translator object for escaping HTML version 4.0.
315     *
316     * While {@link #escapeHtml4(String)} is the expected method of use, this
317     * object allows the HTML escaping functionality to be used
318     * as the foundation for a custom translator.
319     */
320    public static final CharSequenceTranslator ESCAPE_HTML4 =
321            new AggregateTranslator(
322                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
323                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE),
324                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE)
325            );
326    /**
327     * Translator object for escaping individual Comma Separated Values.
328     *
329     * While {@link #escapeCsv(String)} is the expected method of use, this
330     * object allows the CSV escaping functionality to be used
331     * as the foundation for a custom translator.
332     */
333    public static final CharSequenceTranslator ESCAPE_CSV = new CsvTranslators.CsvEscaper();
334
335    /* UNESCAPE TRANSLATORS */
336
337    /**
338     * Translator object for escaping Shell command language.
339     *
340     * @see <a href="https://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
341     */
342    public static final CharSequenceTranslator ESCAPE_XSI;
343    static {
344        final Map<CharSequence, CharSequence> escapeXsiMap = new HashMap<>();
345        escapeXsiMap.put("|", "\\|");
346        escapeXsiMap.put("&", "\\&");
347        escapeXsiMap.put(";", "\\;");
348        escapeXsiMap.put("<", "\\<");
349        escapeXsiMap.put(">", "\\>");
350        escapeXsiMap.put("(", "\\(");
351        escapeXsiMap.put(")", "\\)");
352        escapeXsiMap.put("$", "\\$");
353        escapeXsiMap.put("`", "\\`");
354        escapeXsiMap.put("\\", "\\\\");
355        escapeXsiMap.put("\"", "\\\"");
356        escapeXsiMap.put("'", "\\'");
357        escapeXsiMap.put(" ", "\\ ");
358        escapeXsiMap.put("\t", "\\\t");
359        escapeXsiMap.put("\r\n", StringUtils.EMPTY);
360        escapeXsiMap.put("\n", StringUtils.EMPTY);
361        escapeXsiMap.put("*", "\\*");
362        escapeXsiMap.put("?", "\\?");
363        escapeXsiMap.put("[", "\\[");
364        escapeXsiMap.put("#", "\\#");
365        escapeXsiMap.put("~", "\\~");
366        escapeXsiMap.put("=", "\\=");
367        escapeXsiMap.put("%", "\\%");
368        ESCAPE_XSI = new LookupTranslator(
369                Collections.unmodifiableMap(escapeXsiMap)
370        );
371    }
372
373    /**
374     * Translator object for unescaping escaped Java.
375     *
376     * While {@link #unescapeJava(String)} is the expected method of use, this
377     * object allows the Java unescaping functionality to be used
378     * as the foundation for a custom translator.
379     */
380    public static final CharSequenceTranslator UNESCAPE_JAVA;
381
382    static {
383        final Map<CharSequence, CharSequence> unescapeJavaMap = new HashMap<>();
384        unescapeJavaMap.put("\\\\", "\\");
385        unescapeJavaMap.put("\\\"", "\"");
386        unescapeJavaMap.put("\\'", "'");
387        unescapeJavaMap.put("\\", StringUtils.EMPTY);
388        UNESCAPE_JAVA = new AggregateTranslator(
389                new OctalUnescaper(),     // .between('\1', '\377'),
390                new UnicodeUnescaper(),
391                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE),
392                new LookupTranslator(Collections.unmodifiableMap(unescapeJavaMap))
393        );
394    }
395
396    /**
397     * Translator object for unescaping escaped EcmaScript.
398     *
399     * While {@link #unescapeEcmaScript(String)} is the expected method of use, this
400     * object allows the EcmaScript unescaping functionality to be used
401     * as the foundation for a custom translator.
402     */
403    public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA;
404
405    /**
406     * Translator object for unescaping escaped Json.
407     *
408     * While {@link #unescapeJson(String)} is the expected method of use, this
409     * object allows the Json unescaping functionality to be used
410     * as the foundation for a custom translator.
411     */
412    public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA;
413
414    /**
415     * Translator object for unescaping escaped HTML 3.0.
416     *
417     * While {@link #unescapeHtml3(String)} is the expected method of use, this
418     * object allows the HTML unescaping functionality to be used
419     * as the foundation for a custom translator.
420     */
421    public static final CharSequenceTranslator UNESCAPE_HTML3 =
422            new AggregateTranslator(
423                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
424                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
425                    new NumericEntityUnescaper()
426            );
427
428    /**
429     * Translator object for unescaping escaped HTML 4.0.
430     *
431     * While {@link #unescapeHtml4(String)} is the expected method of use, this
432     * object allows the HTML unescaping functionality to be used
433     * as the foundation for a custom translator.
434     */
435    public static final CharSequenceTranslator UNESCAPE_HTML4 =
436            new AggregateTranslator(
437                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
438                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
439                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
440                    new NumericEntityUnescaper()
441            );
442
443    /**
444     * Translator object for unescaping escaped XML.
445     *
446     * While {@link #unescapeXml(String)} is the expected method of use, this
447     * object allows the XML unescaping functionality to be used
448     * as the foundation for a custom translator.
449     */
450    public static final CharSequenceTranslator UNESCAPE_XML =
451            new AggregateTranslator(
452                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
453                    new LookupTranslator(EntityArrays.APOS_UNESCAPE),
454                    new NumericEntityUnescaper()
455            );
456
457    /**
458     * Translator object for unescaping escaped Comma Separated Value entries.
459     *
460     * While {@link #unescapeCsv(String)} is the expected method of use, this
461     * object allows the CSV unescaping functionality to be used
462     * as the foundation for a custom translator.
463     */
464    public static final CharSequenceTranslator UNESCAPE_CSV = new CsvTranslators.CsvUnescaper();
465
466    /* Helper functions */
467
468    /**
469     * Translator object for unescaping escaped XSI Value entries.
470     *
471     * While {@link #unescapeXSI(String)}  is the expected method of use, this
472     * object allows the XSI unescaping functionality to be used
473     * as the foundation for a custom translator.
474     */
475    public static final CharSequenceTranslator UNESCAPE_XSI = new XsiUnescaper();
476
477    /**
478     * Gets a {@link Builder}.
479     *
480     * @param translator the text translator.
481     * @return {@link Builder}
482     */
483    public static StringEscapeUtils.Builder builder(final CharSequenceTranslator translator) {
484        return new Builder(translator);
485    }
486
487    /**
488     * Returns a {@code String} value for a CSV column enclosed in double quotes, if required.
489     *
490     * <p>
491     * If the value contains a comma, newline or double quote, then the String value is returned enclosed in double quotes.
492     * </p>
493     *
494     * <p>
495     * Any double quote characters in the value are escaped with another double quote.
496     * </p>
497     *
498     * <p>
499     * If the value does not contain a comma, newline or double quote, then the String value is returned unchanged.
500     * </p>
501     * <p>
502     * See <a href="https://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>.
503     * </p>
504     *
505     * @param input the input CSV column String, may be null.
506     * @return The input String, enclosed in double quotes if the value contains a comma, newline or double quote, {@code null} if null string input.
507     */
508    public static String escapeCsv(final String input) {
509        return ESCAPE_CSV.translate(input);
510    }
511
512    /**
513     * Escapes the characters in a {@code String} using EcmaScript String rules.
514     *
515     * <p>
516     * Escapes any values it finds into their EcmaScript String form. Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
517     * </p>
518     *
519     * <p>
520     * So a tab becomes the characters {@code '\\'} and {@code 't'}.
521     * </p>
522     *
523     * <p>
524     * The only difference between Java strings and EcmaScript strings is that in EcmaScript, a single quote and forward-slash (/) are escaped.
525     * </p>
526     *
527     * <p>
528     * Note that EcmaScript is best known by the JavaScript and ActionScript dialects.
529     * </p>
530     *
531     * <p>
532     * Example:
533     * </p>
534     *
535     * <pre>
536     * input string: He didn't say, "Stop!"
537     * output string: He didn\'t say, \"Stop!\"
538     * </pre>
539     * <p>
540     * <strong>Security Note.</strong> We only provide backslash escaping in this method. For example, {@code '\"'} has the output {@code '\\\"'} which could
541     * result in potential issues in the case where the string being escaped is being used in an HTML tag like {@code <select onmouseover="..." />}. If you wish
542     * to have more rigorous string escaping, you may consider the <a href="https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API_JAVA">ESAPI
543     * Libraries</a>. Further, you can view the <a href="https://github.com/esapi">ESAPI GitHub Org</a>.
544     * </p>
545     *
546     * @param input String to escape values in, may be null.
547     * @return String with escaped values, {@code null} if null string input.
548     */
549    public static String escapeEcmaScript(final String input) {
550        return ESCAPE_ECMASCRIPT.translate(input);
551    }
552
553    /**
554     * Escapes the characters in a {@code String} using HTML entities.
555     *
556     * <p>Supports only the HTML 3.0 entities.</p>
557     *
558     * @param input  the {@code String} to escape, may be null.
559     * @return a new escaped {@code String}, {@code null} if null string input.
560     */
561    public static String escapeHtml3(final String input) {
562        return ESCAPE_HTML3.translate(input);
563    }
564
565    // HTML and XML
566    /**
567     * Escapes the characters in a {@code String} using HTML entities.
568     *
569     * <p>
570     * For example:
571     * </p>
572     * <p>{@code "bread" &amp; "butter"}</p>
573     * becomes:
574     * <p>
575     * {@code &quot;bread&quot; &amp;amp; &quot;butter&quot;}.
576     * </p>
577     *
578     * <p>Supports all known HTML 4.0 entities, including funky accents.
579     * Note that the commonly used apostrophe escape character (&amp;apos;)
580     * is not a legal entity and so is not supported).</p>
581     *
582     * @param input  the {@code String} to escape, may be null.
583     * @return a new escaped {@code String}, {@code null} if null string input.
584     * @see <a href="https://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
585     * @see <a href="https://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
586     * @see <a href="https://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
587     * @see <a href="https://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
588     * @see <a href="https://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
589     */
590    public static String escapeHtml4(final String input) {
591        return ESCAPE_HTML4.translate(input);
592    }
593
594    // Java and JavaScript
595    /**
596     * Escapes the characters in a {@code String} using Java String rules.
597     *
598     * <p>
599     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
600     * </p>
601     *
602     * <p>
603     * So a tab becomes the characters {@code '\\'} and {@code 't'}.
604     * </p>
605     *
606     * <p>
607     * The only difference between Java strings and JavaScript strings is that in JavaScript, a single quote and forward-slash (/) are escaped.
608     * </p>
609     *
610     * <p>
611     * Example:
612     * </p>
613     *
614     * <pre>
615     * input string: He didn't say, "Stop!"
616     * output string: He didn't say, \"Stop!\"
617     * </pre>
618     *
619     * @param input String to escape values in, may be null.
620     * @return String with escaped values, {@code null} if null string input.
621     */
622    public static String escapeJava(final String input) {
623        return ESCAPE_JAVA.translate(input);
624    }
625
626    /**
627     * Escapes the characters in a {@code String} using Json String rules.
628     *
629     * <p>
630     * Escapes any values it finds into their Json String form. Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)
631     * </p>
632     *
633     * <p>
634     * So a tab becomes the characters {@code '\\'} and {@code 't'}.
635     * </p>
636     *
637     * <p>
638     * The only difference between Java strings and Json strings is that in Json, forward-slash (/) is escaped.
639     * </p>
640     *
641     * <p>
642     * See http://www.ietf.org/rfc/rfc4627.txt for further details.
643     * </p>
644     *
645     * <p>
646     * Example:
647     * </p>
648     *
649     * <pre>
650     * input string: He didn't say, "Stop!"
651     * output string: He didn't say, \"Stop!\"
652     * </pre>
653     *
654     * @param input String to escape values in, may be null.
655     * @return String with escaped values, {@code null} if null string input.
656     */
657    public static String escapeJson(final String input) {
658        return ESCAPE_JSON.translate(input);
659    }
660
661    /**
662     * Escapes the characters in a {@code String} using XML entities.
663     *
664     * <p>
665     * For example: {@code "bread" & "butter"} =&gt; {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
666     * </p>
667     *
668     * <p>
669     * Note that XML 1.0 is a text-only format: it cannot represent control characters or unpaired Unicode surrogate code points, even after escaping.
670     * {@code escapeXml10} will remove characters that do not fit in the following ranges:
671     * </p>
672     *
673     * <p>
674     * {@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}
675     * </p>
676     *
677     * <p>
678     * Though not strictly necessary, {@code escapeXml10} will escape characters in the following ranges:
679     * </p>
680     *
681     * <p>
682     * {@code [#x7F-#x84] | [#x86-#x9F]}
683     * </p>
684     *
685     * <p>
686     * The returned string can be inserted into a valid XML 1.0 or XML 1.1 document. If you want to allow more non-text characters in an XML 1.1 document, use
687     * {@link #escapeXml11(String)}.
688     * </p>
689     *
690     * @param input the {@code String} to escape, may be null.
691     * @return a new escaped {@code String}, {@code null} if null string input.
692     * @see #unescapeXml(String)
693     */
694    public static String escapeXml10(final String input) {
695        return ESCAPE_XML10.translate(input);
696    }
697
698    /**
699     * Escapes the characters in a {@code String} using XML entities.
700     *
701     * <p>
702     * For example: {@code "bread" & "butter"} =&gt; {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
703     * </p>
704     *
705     * <p>
706     * XML 1.1 can represent certain control characters, but it cannot represent the null byte or unpaired Unicode surrogate code points, even after escaping.
707     * {@code escapeXml11} will remove characters that do not fit in the following ranges:
708     * </p>
709     *
710     * <p>
711     * {@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}
712     * </p>
713     *
714     * <p>
715     * {@code escapeXml11} will escape characters in the following ranges:
716     * </p>
717     *
718     * <p>
719     * {@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]}
720     * </p>
721     *
722     * <p>
723     * The returned string can be inserted into a valid XML 1.1 document. Do not use it for XML 1.0 documents.
724     * </p>
725     *
726     * @param input the {@code String} to escape, may be null.
727     * @return a new escaped {@code String}, {@code null} if null string input.
728     * @see #unescapeXml(String)
729     */
730    public static String escapeXml11(final String input) {
731        return ESCAPE_XML11.translate(input);
732    }
733
734    /**
735     * Escapes the characters in a {@code String} using XSI rules.
736     *
737     * <p>
738     * <strong>Beware!</strong> In most cases you don't want to escape shell commands but use multi-argument methods provided by {@link ProcessBuilder} or
739     * {@link Runtime#exec(String[])} instead.
740     * </p>
741     *
742     * <p>
743     * Example:
744     * </p>
745     *
746     * <pre>
747     * input string: He didn't say, "Stop!"
748     * output string: He\ didn\'t\ say,\ \"Stop!\"
749     * </pre>
750     *
751     * @param input String to escape values in, may be null.
752     * @return String with escaped values, {@code null} if null string input.
753     * @see <a href="https://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
754     */
755    public static String escapeXSI(final String input) {
756        return ESCAPE_XSI.translate(input);
757    }
758
759    /**
760     * Returns a {@code String} value for an unescaped CSV column.
761     *
762     * <p>
763     * If the value is enclosed in double quotes, and contains a comma, newline or double quote, then quotes are removed.
764     * </p>
765     *
766     * <p>
767     * Any double quote escaped characters (a pair of double quotes) are unescaped to just one double quote.
768     * </p>
769     *
770     * <p>
771     * If the value is not enclosed in double quotes, or is and does not contain a comma, newline or double quote, then the String value is returned unchanged.
772     * </p>
773     *
774     * see <a href="https://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>.
775     *
776     * @param input the input CSV column String, may be null.
777     * @return The input String, with enclosing double quotes removed and embedded double quotes unescaped, {@code null} if null string input.
778     */
779    public static String unescapeCsv(final String input) {
780        return UNESCAPE_CSV.translate(input);
781    }
782
783    /**
784     * Unescapes any EcmaScript literals found in the {@code String}.
785     *
786     * <p>
787     * For example, it will turn a sequence of {@code '\'} and {@code 'n'} into a newline character, unless the {@code '\'} is preceded by another {@code '\'}.
788     * </p>
789     *
790     * @param input the {@code String} to unescape, may be null.
791     * @return A new unescaped {@code String}, {@code null} if null string input.
792     * @see #unescapeJava(String)
793     */
794    public static String unescapeEcmaScript(final String input) {
795        return UNESCAPE_ECMASCRIPT.translate(input);
796    }
797
798    /**
799     * Unescapes a string containing entity escapes to a string containing the actual Unicode characters corresponding to the escapes. Supports only HTML 3.0
800     * entities.
801     *
802     * @param input the {@code String} to unescape, may be null.
803     * @return a new unescaped {@code String}, {@code null} if null string input.
804     */
805    public static String unescapeHtml3(final String input) {
806        return UNESCAPE_HTML3.translate(input);
807    }
808
809    /**
810     * Unescapes a string containing entity escapes to a string containing the actual Unicode characters corresponding to the escapes. Supports HTML 4.0
811     * entities.
812     *
813     * <p>
814     * For example, the string {@code "&lt;Fran&ccedil;ais&gt;"} will become {@code "<Fran�ais>"}
815     * </p>
816     *
817     * <p>
818     * If an entity is unrecognized, it is left alone, and inserted verbatim into the result string. e.g. {@code "&gt;&zzzz;x"} will become {@code ">&zzzz;x"}.
819     * </p>
820     *
821     * @param input the {@code String} to unescape, may be null.
822     * @return a new unescaped {@code String}, {@code null} if null string input.
823     */
824    public static String unescapeHtml4(final String input) {
825        return UNESCAPE_HTML4.translate(input);
826    }
827
828    /**
829     * Unescapes any Java literals found in the {@code String}. For example, it will turn a sequence of {@code '\'} and {@code 'n'} into a newline character,
830     * unless the {@code '\'} is preceded by another {@code '\'}.
831     *
832     * @param input the {@code String} to unescape, may be null.
833     * @return a new unescaped {@code String}, {@code null} if null string input.
834     */
835    public static String unescapeJava(final String input) {
836        return UNESCAPE_JAVA.translate(input);
837    }
838
839    /**
840     * Unescapes any Json literals found in the {@code String}.
841     *
842     * <p>
843     * For example, it will turn a sequence of {@code '\'} and {@code 'n'} into a newline character, unless the {@code '\'} is preceded by another {@code '\'}.
844     * </p>
845     *
846     * @param input the {@code String} to unescape, may be null.
847     * @return A new unescaped {@code String}, {@code null} if null string input.
848     * @see #unescapeJava(String)
849     */
850    public static String unescapeJson(final String input) {
851        return UNESCAPE_JSON.translate(input);
852    }
853
854    /**
855     * Unescapes a string containing XML entity escapes to a string containing the actual Unicode characters corresponding to the escapes.
856     *
857     * <p>
858     * Supports only the five basic XML entities (gt, lt, quot, amp, apos). Does not support DTDs or external entities.
859     * </p>
860     *
861     * <p>
862     * Note that numerical \\u Unicode codes are unescaped to their respective Unicode characters. This may change in future releases.
863     * </p>
864     *
865     * @param input the {@code String} to unescape, may be null.
866     * @return a new unescaped {@code String}, {@code null} if null string input.
867     * @see #escapeXml10(String)
868     * @see #escapeXml11(String)
869     */
870    public static String unescapeXml(final String input) {
871        return UNESCAPE_XML.translate(input);
872    }
873
874    /**
875     * Unescapes the characters in a {@code String} using XSI rules.
876     *
877     * @param input the {@code String} to unescape, may be null.
878     * @return a new unescaped {@code String}, {@code null} if null string input.
879     * @see StringEscapeUtils#escapeXSI(String)
880     */
881    public static String unescapeXSI(final String input) {
882        return UNESCAPE_XSI.translate(input);
883    }
884
885    /**
886     * {@code StringEscapeUtils} instances should NOT be constructed in standard programming.
887     *
888     * <p>
889     * Instead, the class should be used as:
890     * </p>
891     *
892     * <pre>
893     * StringEscapeUtils.escapeJava("foo");
894     * </pre>
895     *
896     * <p>
897     * This constructor is public to permit tools that require a JavaBean instance to operate.
898     * </p>
899     */
900    public StringEscapeUtils() {
901    }
902
903}